提交 721bf925 编写于 作者: study夏羽's avatar study夏羽

更新依赖插件

上级 edf7f391
......@@ -47,6 +47,13 @@
}
}
},
data() {
return {
focusCaptchaInput: false,
captchaBase64: "",
loging: false
};
},
watch: {
scene: {
handler(scene) {
......@@ -113,16 +120,6 @@
background-color: #FEFAE7;
}
.captcha {
height: 44px;
line-height: 44px;
}
.captcha-img-box {
position: relative;
background-color: #FEFAE7;
}
.captcha {
background-color: #F8F8F8;
font-size: 14px;
......
## 0.0.3(2022-11-11)
- 修复 config 方法获取根节点为数组格式配置时错误的转化为了对象的Bug
## 0.0.2(2021-04-16)
- 修改插件package信息
## 0.0.1(2021-03-15)
......
{
"id": "uni-config-center",
"displayName": "uni-config-center",
"version": "0.0.2",
"version": "0.0.3",
"description": "uniCloud 配置中心",
"keywords": [
"配置",
......@@ -11,11 +11,7 @@
"engines": {
"HBuilderX": "^3.1.0"
},
"dcloudext": {
"category": [
"uniCloud",
"云函数模板"
],
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
......@@ -32,7 +28,8 @@
"data": "无",
"permissions": "无"
},
"npmurl": ""
"npmurl": "",
"type": "unicloud-template-function"
},
"directories": {
"example": "../../../scripts/dist"
......@@ -73,6 +70,10 @@
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "u"
}
}
}
......
{
"name": "uni-config-center",
"version": "0.0.2",
"version": "0.0.3",
"description": "配置中心",
"main": "index.js",
"keywords": [],
......
## 1.1.3(2022-09-22)
- 修复,引入 uni.scss 引入默认主题色报错的问题
## 1.1.2(2022-09-22)
- 增加主题色 primaryColor 配置选项
## 1.1.1(2022-09-19)
- 修复,输入后回车,change 事件触发两次,[详情](https://ask.dcloud.net.cn/question/152149)
## 1.1.4(2022-10-27)
- 修复 props 中背景颜色无默认值的bug
## 1.1.0(2022-06-30)
- 新增 在 uni-forms 1.4.0 中使用可以在 blur 时校验内容
- 新增 clear 事件,点击右侧叉号图标触发
- 新增 change 事件 ,仅在输入框失去焦点或用户按下回车时触发
- 优化 组件样式,组件获取焦点时高亮显示,图标颜色调整等
-
## 1.0.5(2022-06-07)
- 优化 clearable 显示策略
## 1.0.4(2022-06-07)
- 优化 clearable 显示策略
## 1.0.3(2022-05-20)
- 修复 关闭图标某些情况下无法取消的bug
- 修复 关闭图标某些情况下无法取消的 bug
## 1.0.2(2022-04-12)
- 修复 默认值不生效的bug
- 修复 默认值不生效的 bug
## 1.0.1(2022-04-02)
- 修复 value不能为0的bug
- 修复 value 不能为 0 的 bug
## 1.0.0(2021-11-19)
- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 优化 组件 UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-easyinput](https://uniapp.dcloud.io/component/uniui/uni-easyinput)
## 0.1.4(2021-08-20)
- 修复 在 uni-forms 的动态表单中默认值校验不通过的 bug
## 0.1.3(2021-08-11)
- 修复 在 uni-forms 中重置表单,错误信息无法清除的问题
## 0.1.2(2021-07-30)
- 优化 vue3下事件警告的问题
- 优化 vue3 下事件警告的问题
## 0.1.1
- 优化 errorMessage 属性支持 Boolean 类型
## 0.1.0(2021-07-13)
- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
- 组件兼容 vue3,如何创建 vue3 项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 0.0.16(2021-06-29)
- 修复 confirmType 属性(仅 type="text" 生效)导致多行文本框无法换行的 bug
## 0.0.15(2021-06-21)
- 修复 passwordIcon 属性拼写错误的 bug
## 0.0.14(2021-06-18)
- 新增 passwordIcon 属性,当type=password时是否显示小眼睛图标
- 新增 passwordIcon 属性,当 type=password 时是否显示小眼睛图标
- 修复 confirmType 属性不生效的问题
## 0.0.13(2021-06-04)
- 修复 disabled 状态可清出内容的 bug
## 0.0.12(2021-05-12)
- 新增 组件示例地址
## 0.0.11(2021-05-07)
- 修复 input-border 属性不生效的问题
## 0.0.10(2021-04-30)
- 修复 ios 遮挡文字、显示一半的问题
## 0.0.9(2021-02-05)
- 调整为uni_modules目录规范
- 调整为 uni_modules 目录规范
- 优化 兼容 nvue 页面
<template>
<view class="uni-easyinput" :class="{'uni-easyinput-error':msg}" :style="boxStyle">
<view class="uni-easyinput" :class="{ 'uni-easyinput-error': msg }" :style="boxStyle">
<view class="uni-easyinput__content" :class="inputContentClass" :style="inputContentStyle">
<uni-icons v-if="prefixIcon" class="content-clear-icon" :type="prefixIcon" color="#c0c4cc"
@click="onClickIcon('prefix')" size="22"></uni-icons>
<textarea v-if="type === 'textarea'" class="uni-easyinput__content-textarea"
:class="{'input-padding':inputBorder}" :name="name" :value="val" :placeholder="placeholder"
:placeholderStyle="placeholderStyle" :disabled="disabled"
placeholder-class="uni-easyinput__placeholder-class" :maxlength="inputMaxlength" :focus="focused"
:autoHeight="autoHeight" @input="onInput" @blur="_Blur" @focus="_Focus" @confirm="onConfirm"></textarea>
<input v-else :type="type === 'password'?'text':type" class="uni-easyinput__content-input"
:style="inputStyle" :name="name" :value="val" :password="!showPassword && type === 'password'"
:placeholder="placeholder" :placeholderStyle="placeholderStyle"
placeholder-class="uni-easyinput__placeholder-class" :disabled="disabled" :maxlength="inputMaxlength"
:focus="focused" :confirmType="confirmType" @focus="_Focus" @blur="_Blur" @input="onInput"
@confirm="onConfirm" />
<uni-icons v-if="prefixIcon" class="content-clear-icon" :type="prefixIcon" color="#c0c4cc" @click="onClickIcon('prefix')" size="22"></uni-icons>
<textarea
v-if="type === 'textarea'"
class="uni-easyinput__content-textarea"
:class="{ 'input-padding': inputBorder }"
:name="name"
:value="val"
:placeholder="placeholder"
:placeholderStyle="placeholderStyle"
:disabled="disabled"
placeholder-class="uni-easyinput__placeholder-class"
:maxlength="inputMaxlength"
:focus="focused"
:autoHeight="autoHeight"
@input="onInput"
@blur="_Blur"
@focus="_Focus"
@confirm="onConfirm"
></textarea>
<input
v-else
:type="type === 'password' ? 'text' : type"
class="uni-easyinput__content-input"
:style="inputStyle"
:name="name"
:value="val"
:password="!showPassword && type === 'password'"
:placeholder="placeholder"
:placeholderStyle="placeholderStyle"
placeholder-class="uni-easyinput__placeholder-class"
:disabled="disabled"
:maxlength="inputMaxlength"
:focus="focused"
:confirmType="confirmType"
@focus="_Focus"
@blur="_Blur"
@input="onInput"
@confirm="onConfirm"
/>
<template v-if="type === 'password' && passwordIcon">
<!-- 开启密码时显示小眼睛 -->
<uni-icons v-if="isVal" class="content-clear-icon" :class="{'is-textarea-icon':type==='textarea'}"
:type="showPassword?'eye-slash-filled':'eye-filled'" :size="22"
:color="focusShow ? primaryColor :'#c0c4cc'" @click="onEyes">
</uni-icons>
<uni-icons
v-if="isVal"
class="content-clear-icon"
:class="{ 'is-textarea-icon': type === 'textarea' }"
:type="showPassword ? 'eye-slash-filled' : 'eye-filled'"
:size="22"
:color="focusShow ? primaryColor : '#c0c4cc'"
@click="onEyes"
></uni-icons>
</template>
<template v-else-if="suffixIcon">
<uni-icons v-if="suffixIcon" class="content-clear-icon" :type="suffixIcon" color="#c0c4cc"
@click="onClickIcon('suffix')" size="22"></uni-icons>
<uni-icons v-if="suffixIcon" class="content-clear-icon" :type="suffixIcon" color="#c0c4cc" @click="onClickIcon('suffix')" size="22"></uni-icons>
</template>
<template v-else>
<uni-icons v-if="clearable && isVal && !disabled && type !== 'textarea'" class="content-clear-icon"
:class="{'is-textarea-icon':type==='textarea'}" type="clear" :size="clearSize"
:color="msg?'#dd524d':(focusShow? primaryColor :'#c0c4cc')" @click="onClear"></uni-icons>
<uni-icons
v-if="clearable && isVal && !disabled && type !== 'textarea'"
class="content-clear-icon"
:class="{ 'is-textarea-icon': type === 'textarea' }"
type="clear"
:size="clearSize"
:color="msg ? '#dd524d' : focusShow ? primaryColor : '#c0c4cc'"
@click="onClear"
></uni-icons>
</template>
<slot name="right"></slot>
</view>
......@@ -36,7 +72,7 @@
</template>
<script>
/**
/**
* Easyinput 输入框
* @description 此组件可以实现表单的输入与校验,包括 "text" 和 "textarea" 类型。
* @tutorial https://ext.dcloud.net.cn/plugin?id=3455
......@@ -78,26 +114,26 @@
* @event {Function} iconClick 点击图标时触发
* @example <uni-easyinput v-model="mobile"></uni-easyinput>
*/
function obj2strClass(obj) {
let classess = ''
function obj2strClass(obj) {
let classess = '';
for (let key in obj) {
const val = obj[key]
const val = obj[key];
if (val) {
classess += `${key} `
}
classess += `${key} `;
}
return classess
}
return classess;
}
function obj2strStyle(obj) {
let style = ''
function obj2strStyle(obj) {
let style = '';
for (let key in obj) {
const val = obj[key]
style += `${key}:${val};`
const val = obj[key];
style += `${key}:${val};`;
}
return style
}
export default {
return style;
}
export default {
name: 'uni-easyinput',
emits: ['click', 'iconClick', 'update:modelValue', 'input', 'focus', 'blur', 'confirm', 'clear', 'eyes', 'change'],
model: {
......@@ -115,7 +151,7 @@
formItem: {
from: 'uniFormItem',
default: null
},
}
},
props: {
name: String,
......@@ -184,12 +220,13 @@
},
styles: {
type: Object,
default () {
default() {
return {
color: '#333',
backgroundColor: '#fff',
disableColor: '#F7F6F6',
borderColor: '#e5e5e5'
}
};
}
},
errorMessage: {
......@@ -214,12 +251,12 @@
computed: {
// 输入框内是否有值
isVal() {
const val = this.val
const val = this.val;
// fixed by mehaotian 处理值为0的情况,字符串0不在处理范围
if (val || val === 0) {
return true
return true;
}
return false
return false;
},
msg() {
......@@ -228,7 +265,7 @@
// return this.errorMessage || this.formItem.errMsg;
// }
// TODO 处理头条 formItem 中 errMsg 不更新的问题
return this.localMsg || this.errorMessage
return this.localMsg || this.errorMessage;
},
// 因为uniapp的input组件的maxlength组件必须要数值,这里转为数值,用户可以传入字符串数值
inputMaxlength() {
......@@ -237,7 +274,7 @@
// 处理外层样式的style
boxStyle() {
return `color:${this.inputBorder && this.msg?'#e43d33':this.styles.color};`
return `color:${this.inputBorder && this.msg ? '#e43d33' : this.styles.color};`;
},
// input 内容的类和样式处理
inputContentClass() {
......@@ -246,53 +283,53 @@
'is-input-error-border': this.inputBorder && this.msg,
'is-textarea': this.type === 'textarea',
'is-disabled': this.disabled
})
});
},
inputContentStyle() {
const focusColor = this.focusShow ? this.primaryColor : this.styles.borderColor
const borderColor = this.inputBorder && this.msg ? '#dd524d' : focusColor
const focusColor = this.focusShow ? this.primaryColor : this.styles.borderColor;
const borderColor = this.inputBorder && this.msg ? '#dd524d' : focusColor;
return obj2strStyle({
'border-color': borderColor || '#e5e5e5',
'background-color': this.disabled ? this.styles.disableColor : '#fff'
})
'background-color': this.disabled ? this.styles.disableColor : this.styles.backgroundColor
});
},
// input右侧样式
inputStyle() {
const paddingRight = this.type === 'password' || this.clearable || this.prefixIcon ? '' : '10px'
const paddingRight = this.type === 'password' || this.clearable || this.prefixIcon ? '' : '10px';
return obj2strStyle({
'padding-right': paddingRight,
'padding-left': this.prefixIcon ? '' : '10px'
})
});
}
},
watch: {
value(newVal) {
this.val = newVal
this.val = newVal;
},
modelValue(newVal) {
this.val = newVal
this.val = newVal;
},
focus(newVal) {
this.$nextTick(() => {
this.focused = this.focus
this.focusShow = this.focus
})
this.focused = this.focus;
this.focusShow = this.focus;
});
}
},
created() {
this.init()
this.init();
// TODO 处理头条vue3 computed 不监听 inject 更改的问题(formItem.errMsg)
if (this.form && this.formItem) {
this.$watch('formItem.errMsg', (newVal) => {
this.localMsg = newVal
})
this.$watch('formItem.errMsg', newVal => {
this.localMsg = newVal;
});
}
},
mounted() {
this.$nextTick(() => {
this.focused = this.focus
this.focusShow = this.focus
})
this.focused = this.focus;
this.focusShow = this.focus;
});
},
methods: {
/**
......@@ -300,11 +337,11 @@
*/
init() {
if (this.value || this.value === 0) {
this.val = this.value
this.val = this.value;
} else if (this.modelValue || this.modelValue === 0) {
this.val = this.modelValue
this.val = this.modelValue;
} else {
this.val = null
this.val = null;
}
},
......@@ -313,15 +350,15 @@
* @param {Object} type
*/
onClickIcon(type) {
this.$emit('iconClick', type)
this.$emit('iconClick', type);
},
/**
* 显示隐藏内容,密码框时生效
*/
onEyes() {
this.showPassword = !this.showPassword
this.$emit('eyes', this.showPassword)
this.showPassword = !this.showPassword;
this.$emit('eyes', this.showPassword);
},
/**
......@@ -332,19 +369,19 @@
let value = event.detail.value;
// 判断是否去除空格
if (this.trim) {
if (typeof(this.trim) === 'boolean' && this.trim) {
value = this.trimStr(value)
if (typeof this.trim === 'boolean' && this.trim) {
value = this.trimStr(value);
}
if (typeof(this.trim) === 'string') {
value = this.trimStr(value, this.trim)
if (typeof this.trim === 'string') {
value = this.trimStr(value, this.trim);
}
};
if (this.errMsg) this.errMsg = ''
this.val = value
}
if (this.errMsg) this.errMsg = '';
this.val = value;
// TODO 兼容 vue2
this.$emit('input', value);
// TODO 兼容 vue3
this.$emit('update:modelValue', value)
this.$emit('update:modelValue', value);
},
/**
......@@ -354,13 +391,13 @@
*/
onFocus() {
this.$nextTick(() => {
this.focused = true
})
this.focused = true;
});
this.$emit('focus', null);
},
_Focus(event) {
this.focusShow = true
this.focusShow = true;
this.$emit('focus', event);
},
......@@ -370,24 +407,22 @@
* @param {Object} event
*/
onBlur() {
this.focused = false
this.focused = false;
this.$emit('focus', null);
},
_Blur(event) {
let value = event.detail.value;
this.focusShow = false
this.focusShow = false;
this.$emit('blur', event);
// 根据类型返回值,在event中获取的值理论上讲都是string
if (this.isEnter === false) {
this.$emit('change', this.val)
this.$emit('change', this.val);
}
// 失去焦点时参与表单校验
if (this.form && this.formItem) {
const {
validateTrigger
} = this.form
const { validateTrigger } = this.form;
if (validateTrigger === 'blur') {
this.formItem.onFieldChange()
this.formItem.onFieldChange();
}
}
},
......@@ -399,10 +434,10 @@
onConfirm(e) {
this.$emit('confirm', this.val);
this.isEnter = true;
this.$emit('change', this.val)
this.$emit('change', this.val);
this.$nextTick(() => {
this.isEnter = false
})
this.isEnter = false;
});
},
/**
......@@ -415,9 +450,9 @@
this.$emit('input', '');
// TODO 兼容 vue2
// TODO 兼容 vue3
this.$emit('update:modelValue', '')
this.$emit('update:modelValue', '');
// 点击叉号触发
this.$emit('clear')
this.$emit('clear');
},
/**
......@@ -431,9 +466,9 @@
} else if (pos === 'right') {
return str.trimRight();
} else if (pos === 'start') {
return str.trimStart()
return str.trimStart();
} else if (pos === 'end') {
return str.trimEnd()
return str.trimEnd();
} else if (pos === 'all') {
return str.replace(/\s+/g, '');
} else if (pos === 'none') {
......@@ -442,14 +477,14 @@
return str;
}
}
};
};
</script>
<style lang="scss">
$uni-error: #e43d33;
$uni-border-1: #DCDFE6 !default;
$uni-error: #e43d33;
$uni-border-1: #dcdfe6 !default;
.uni-easyinput {
.uni-easyinput {
/* #ifndef APP-NVUE */
width: 100%;
/* #endif */
......@@ -458,9 +493,9 @@
text-align: left;
color: #333;
font-size: 14px;
}
}
.uni-easyinput__content {
.uni-easyinput__content {
flex: 1;
/* #ifndef APP-NVUE */
width: 100%;
......@@ -474,9 +509,9 @@
border-color: #fff;
transition-property: border-color;
transition-duration: 0.3s;
}
}
.uni-easyinput__content-input {
.uni-easyinput__content-input {
/* #ifndef APP-NVUE */
width: auto;
/* #endif */
......@@ -487,23 +522,23 @@
font-size: 14px;
height: 35px;
// min-height: 36px;
}
}
.uni-easyinput__placeholder-class {
.uni-easyinput__placeholder-class {
color: #999;
font-size: 12px;
// font-weight: 200;
}
}
.is-textarea {
.is-textarea {
align-items: flex-start;
}
}
.is-textarea-icon {
.is-textarea-icon {
margin-top: 5px;
}
}
.uni-easyinput__content-textarea {
.uni-easyinput__content-textarea {
position: relative;
overflow: hidden;
flex: 1;
......@@ -517,23 +552,23 @@
min-height: 80px;
width: auto;
/* #endif */
}
}
.input-padding {
.input-padding {
padding-left: 10px;
}
}
.content-clear-icon {
.content-clear-icon {
padding: 0 5px;
}
}
.label-icon {
.label-icon {
margin-right: 5px;
margin-top: -1px;
}
}
// 显示边框
.is-input-border {
// 显示边框
.is-input-border {
/* #ifndef APP-NVUE */
display: flex;
box-sizing: border-box;
......@@ -545,9 +580,9 @@
/* #ifdef MP-ALIPAY */
overflow: hidden;
/* #endif */
}
}
.uni-error-message {
.uni-error-message {
position: absolute;
bottom: -17px;
left: 0;
......@@ -555,51 +590,49 @@
color: $uni-error;
font-size: 12px;
text-align: left;
}
}
.uni-error-msg--boeder {
.uni-error-msg--boeder {
position: relative;
bottom: 0;
line-height: 22px;
}
}
.is-input-error-border {
.is-input-error-border {
border-color: $uni-error;
.uni-easyinput__placeholder-class {
color: mix(#fff, $uni-error, 50%);
;
}
}
}
.uni-easyinput--border {
.uni-easyinput--border {
margin-bottom: 0;
padding: 10px 15px;
// padding-bottom: 0;
border-top: 1px #eee solid;
}
}
.uni-easyinput-error {
.uni-easyinput-error {
padding-bottom: 0;
}
}
.is-first-border {
.is-first-border {
/* #ifndef APP-NVUE */
border: none;
/* #endif */
/* #ifdef APP-NVUE */
border-width: 0;
/* #endif */
}
}
.is-disabled {
background-color: #F7F6F6;
color: #D5D5D5;
.is-disabled {
background-color: #f7f6f6;
color: #d5d5d5;
.uni-easyinput__placeholder-class {
color: #D5D5D5;
color: #d5d5d5;
font-size: 12px;
}
}
}
</style>
{
"id": "uni-easyinput",
"displayName": "uni-easyinput 增强输入框",
"version": "1.1.3",
"version": "1.1.4",
"description": "Easyinput 组件是对原生input组件的增强",
"keywords": [
"uni-ui",
......
## 1.0.30(2022-11-11)
- uni-id-co 修复 用户只有openid时绑定微信/QQ报错
## 1.0.29(2022-11-10)
- uni-id-co 支持URL化方式请求 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#adapter-http)
## 1.0.28(2022-11-09)
- uni-id-co 升级密码加密算法,支持hmac-sha256加密 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id-summary.html#password-safe)
- uni-id-co 新增 开发者可以自定义密码加密规则 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id-summary.html#custom-password-encrypt)
- uni-id-co 新增 支持将其他系统用户迁移至uni-id [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id-summary.html#move-users-to-uni-id)
## 1.0.27(2022-10-26)
- uni-id-co 新增 secureNetworkHandshakeByWeixin 接口,用于建立和微信小程序的安全网络连接
## 1.0.26(2022-10-18)
- 修复 uni-id-pages 导入时异常的Bug
## 1.0.25(2022-10-14)
......
......@@ -56,7 +56,6 @@ export default async function() {
}
// #endif
/* 注释此代码块原因:与uni-starter中的appinit逻辑一致
//3. 绑定clientDB错误事件
// clientDB对象
const db = uniCloud.database()
......@@ -73,9 +72,9 @@ export default async function() {
}
// 解绑clientDB错误事件
//db.off('error', onDBError)
*/
//4. 同步客户端push_clientid至uni-id-device表
//4. 同步客户端push_clientid至device表
if (uniCloud.onRefreshToken) {
uniCloud.onRefreshToken(() => {
console.log('onRefreshToken');
......@@ -91,7 +90,7 @@ export default async function() {
console.log('getPushClientId', res);
},
fail(e) {
console.error(e,'更多详情:https://uniapp.dcloud.net.cn/uniCloud/uni-starter.html#%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9')
console.log(e)
}
})
}
......
{
"id": "uni-id-pages",
"displayName": "uni-id-pages",
"version": "1.0.26",
"version": "1.0.30",
"description": "云端一体简单、统一、可扩展的用户中心页面模版",
"keywords": [
"用户管理",
......
......@@ -6,6 +6,8 @@ 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',
......@@ -78,6 +80,7 @@ module.exports = {
userCollection,
verifyCollection,
deviceCollection,
openDataCollection,
USER_IDENTIFIER,
USER_STATUS,
CAPTCHA_SCENE,
......
......@@ -35,7 +35,8 @@ const ERROR = {
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'
UNBIND_MOBILE_NOT_EXISTS: 'uni-id-unbind-mobile-not-exists',
UNSUPPORTED_REQUEST: 'uni-id-unsupported-request'
}
function isUniIdError (errCode) {
......
const { ERROR } = require('./error')
function getHttpClientInfo () {
const requestId = this.getUniCloudRequestId()
const { clientIP, userAgent, source, secretType = 'none' } = this.getClientInfo()
const { clientInfo = {} } = JSON.parse(this.getHttpInfo().body)
return {
...clientInfo,
clientIP,
userAgent,
source,
secretType,
requestId
}
}
function getHttpUniIdToken () {
const { uniIdToken = '' } = JSON.parse(this.getHttpInfo().body)
return uniIdToken
}
function verifyHttpMethod () {
const { headers, httpMethod } = this.getHttpInfo()
if (!/^application\/json/.test(headers['content-type']) || httpMethod.toUpperCase() !== 'POST') {
throw {
errCode: ERROR.UNSUPPORTED_REQUEST,
errMsg: 'unsupported request'
}
}
}
function universal () {
if (this.getClientInfo().source === 'http') {
verifyHttpMethod.call(this)
this.getParams()[0] = JSON.parse(this.getHttpInfo().body).params
this.getUniversalClientInfo = getHttpClientInfo.bind(this)
this.getUniversalUniIdToken = getHttpUniIdToken.bind(this)
} else {
this.getUniversalClientInfo = this.getClientInfo
this.getUniversalUniIdToken = this.getUniIdToken
}
}
module.exports = universal
......@@ -12,6 +12,7 @@ const {
isUniIdError
} = require('./common/error')
const middleware = require('./middleware/index')
const universal = require('./common/universal')
const {
registerAdmin,
......@@ -63,7 +64,8 @@ const {
} = require('./module/verify/index')
const {
refreshToken,
setPushCid
setPushCid,
secureNetworkHandshakeByWeixin
} = require('./module/utils/index')
const {
getInvitedUser,
......@@ -80,7 +82,10 @@ const {
module.exports = {
async _before () {
const clientInfo = this.getClientInfo()
// 支持 callFunction 与 URL化
universal.call(this)
const clientInfo = this.getUniversalClientInfo()
/**
* 检查clientInfo,无appId和uniPlatform时本云对象无法正常运行
* 此外需要保证用到的clientInfo字段均经过类型检查
......@@ -576,5 +581,9 @@ module.exports = {
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#unbind-apple
* @returns
*/
unbindApple
unbindApple,
/**
* 安全网络握手,目前仅处理微信小程序安全网络握手
*/
secureNetworkHandshakeByWeixin
}
......@@ -40,7 +40,8 @@ const sentence = {
'uni-id-unbind-failed': 'Please bind first and then unbind',
'uni-id-unbind-not-supported': 'Unbinding is not supported',
'uni-id-unbind-mobile-not-exists': 'This is the only way to login at the moment, please bind your phone number and then try to unbind',
'uni-id-unbind-password-not-exists': 'Please set a password first'
'uni-id-unbind-password-not-exists': 'Please set a password first',
'uni-id-unsupported-request': 'Unsupported request'
}
module.exports = {
......
......@@ -40,7 +40,8 @@ const sentence = {
'uni-id-unbind-failed': '请先绑定后再解绑',
'uni-id-unbind-not-supported': '不支持解绑',
'uni-id-unbind-mobile-not-exists': '这是当前唯一登录方式,请绑定手机号后再尝试解绑',
'uni-id-unbind-password-not-exists': '请先设置密码在尝试解绑'
'uni-id-unbind-password-not-exists': '请先设置密码在尝试解绑',
'uni-id-unsupported-request': '不支持的请求方式'
}
module.exports = {
......
......@@ -39,7 +39,7 @@ async function getNeedCaptcha ({
const {
data: recentRecord
} = await uniIdLogCollection.where({
ip: this.getClientInfo().clientIP,
ip: this.getUniversalClientInfo().clientIP,
...userIdentifier,
type,
create_date: dbCmd.gt(now - limitDuration)
......@@ -61,7 +61,7 @@ async function verifyCaptcha (params = {}) {
}
}
const payload = await this.uniCaptcha.verify({
deviceId: this.getClientInfo().deviceId,
deviceId: this.getUniversalClientInfo().deviceId,
captcha,
scene
})
......
......@@ -17,7 +17,7 @@ async function realPreLogin (params = {}) {
const {
user
} = params
const appId = this.getClientInfo().appId
const appId = this.getUniversalClientInfo().appId
const userMatched = await findUser({
userQuery: user,
authorizedApp: appId
......@@ -66,7 +66,7 @@ async function preLoginWithPassword (params = {}) {
} = this.config
const {
clientIP
} = this.getClientInfo()
} = this.getUniversalClientInfo()
// 根据ip地址,密码错误次数过多,锁定登录
let loginIPLimit = userRecord.login_ip_limit || []
// 清理无用记录
......@@ -78,6 +78,8 @@ async function preLoginWithPassword (params = {}) {
}
}
const passwordUtils = new PasswordUtils({
userRecord,
clientInfo: this.getUniversalClientInfo(),
passwordSecret: this.config.passwordSecret
})
......@@ -85,9 +87,7 @@ async function preLoginWithPassword (params = {}) {
success: checkPasswordSuccess,
refreshPasswordInfo
} = passwordUtils.checkUserPassword({
password,
passwordHash: userRecord.password,
passwordSecretVersion: userRecord.password_secret_version
password
})
if (!checkPasswordSuccess) {
// 更新用户ip对应的密码错误记录
......@@ -179,7 +179,7 @@ async function postLogin (params = {}) {
const {
clientIP,
uniIdToken
} = this.getClientInfo()
} = this.getUniversalClientInfo()
const uid = user._id
const updateData = {
last_login_date: Date.now(),
......
......@@ -5,11 +5,11 @@ const {
userCollection
} = require('../../common/constants')
async function logout() {
async function logout () {
const {
uniIdToken,
deviceId
} = this.getClientInfo()
} = this.getUniversalClientInfo()
const {
uid
} = await this.uniIdCommon.checkToken(
......
......@@ -2,37 +2,160 @@ const {
getType
} = require('../../common/utils')
const crypto = require('crypto')
const createConfig = require('uni-config-center')
const shareConfig = createConfig({
pluginId: 'uni-id'
})
let customPassword = {}
if (shareConfig.hasFile('custom-password.js')) {
customPassword = shareConfig.requireFile('custom-password.js') || {}
}
const passwordAlgorithmMap = {
UNI_ID_HMAC_SHA1: 'hmac-sha1',
UNI_ID_HMAC_SHA256: 'hmac-sha256',
UNI_ID_CUSTOM: 'custom'
}
const passwordAlgorithmKeyMap = Object.keys(passwordAlgorithmMap).reduce((res, item) => {
res[passwordAlgorithmMap[item]] = item
return res
}, {})
const passwordExtMethod = {
[passwordAlgorithmMap.UNI_ID_HMAC_SHA1]: {
verify ({ password }) {
const { password_secret_version: passwordSecretVersion } = this.userRecord
const passwordSecret = this._getSecretByVersion({
version: passwordSecretVersion
})
const { passwordHash } = this.encrypt({
password,
passwordSecret
})
const PasswordHashMethod = {
'hmac-sha1': function (content, secret) {
return passwordHash === this.userRecord.password
},
encrypt ({ password, passwordSecret }) {
const { value: secret, version } = passwordSecret
const hmac = crypto.createHmac('sha1', secret.toString('ascii'))
hmac.update(content)
return hmac.digest('hex')
hmac.update(password)
return {
passwordHash: hmac.digest('hex'),
version
}
}
},
[passwordAlgorithmMap.UNI_ID_HMAC_SHA256]: {
verify ({ password }) {
const parse = this._parsePassword()
const passwordHash = crypto.createHmac(parse.algorithm, parse.salt).update(password).digest('hex')
return passwordHash === parse.hash
},
encrypt ({ password, passwordSecret }) {
const { version } = passwordSecret
// 默认使用 sha256 加密算法
const salt = crypto.randomBytes(10).toString('hex')
const sha256Hash = crypto.createHmac(passwordAlgorithmMap.UNI_ID_HMAC_SHA256.substring(5), salt).update(password).digest('hex')
const algorithm = passwordAlgorithmKeyMap[passwordAlgorithmMap.UNI_ID_HMAC_SHA256]
// B 为固定值,对应 PasswordMethodMaps 中的 sha256算法
// hash 格式 $[PasswordMethodFlagMapsKey]$[salt size]$[salt][Hash]
const passwordHash = `$${algorithm}$${salt.length}$${salt}${sha256Hash}`
return {
passwordHash,
version
}
}
},
[passwordAlgorithmMap.UNI_ID_CUSTOM]: {
verify ({ password, passwordSecret }) {
if (!customPassword.verifyPassword) throw new Error('verifyPassword method not found in custom password file')
// return true or false
return customPassword.verifyPassword({
password,
passwordSecret,
userRecord: this.userRecord,
clientInfo: this.clientInfo
})
},
encrypt ({ password, passwordSecret }) {
if (!customPassword.encryptPassword) throw new Error('encryptPassword method not found in custom password file')
// return object<{passwordHash: string, version: number}>
return customPassword.encryptPassword({
password,
passwordSecret,
clientInfo: this.clientInfo
})
}
}
}
class PasswordUtils {
constructor ({
userRecord = {},
clientInfo,
passwordSecret
} = {}) {
const passwordSecretType = getType(passwordSecret)
if (passwordSecretType === 'array') {
this.passwordSecret = passwordSecret.sort((a, b) => {
return a.version - b.version
if (!clientInfo) throw new Error('Invalid clientInfo')
if (!passwordSecret) throw new Error('Invalid password secret')
this.clientInfo = clientInfo
this.userRecord = userRecord
this.passwordSecret = this.prePasswordSecret(passwordSecret)
}
/**
* passwordSecret 预处理
* @param passwordSecret
* @return {*[]}
*/
prePasswordSecret (passwordSecret) {
const newPasswordSecret = []
if (getType(passwordSecret) === 'string') {
newPasswordSecret.push({
value: passwordSecret,
type: passwordAlgorithmMap.UNI_ID_HMAC_SHA1
})
} else if (getType(passwordSecret) === 'array') {
for (const secret of passwordSecret.sort((a, b) => a.version - b.version)) {
newPasswordSecret.push({
...secret,
// 没有 type 设置默认 type hmac-sha1
type: secret.type || passwordAlgorithmMap.UNI_ID_HMAC_SHA1
})
} else if (passwordSecretType === 'string') {
this.passwordSecret = [{ value: passwordSecret }]
}
} else {
throw new Error('Invalid password secret')
}
return newPasswordSecret
}
getSecretByVersion (params = {}) {
const {
version
} = params
/**
* 获取最新加密密钥
* @return {*}
* @private
*/
_getLastestSecret () {
return this.passwordSecret[this.passwordSecret.length - 1]
}
_getOldestSecret () {
return this.passwordSecret[0]
}
_getSecretByVersion ({ version } = {}) {
if (!version && version !== 0) {
return this.getOldestSecret()
return this._getOldestSecret()
}
if (this.passwordSecret.length === 1) {
return this.passwordSecret[0]
......@@ -40,75 +163,97 @@ class PasswordUtils {
return this.passwordSecret.find(item => item.version === version)
}
getLastestSecret () {
return this.passwordSecret[this.passwordSecret.length - 1]
/**
* 获取密码的验证/加密方法
* @param passwordSecret
* @return {*[]}
* @private
*/
_getPasswordExt (passwordSecret) {
const ext = passwordExtMethod[passwordSecret.type]
if (!ext) {
throw new Error(`暂不支持 ${passwordSecret.type} 类型的加密算法`)
}
getOldestSecret () {
return this.passwordSecret[0]
const passwordExt = Object.create(null)
for (const key in ext) {
passwordExt[key] = ext[key].bind(Object.assign(this, Object.keys(ext).reduce((res, item) => {
if (item !== key) {
res[item] = ext[item].bind(this)
}
return res
}, {})))
}
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 passwordExt
}
_parsePassword () {
const [algorithmKey = '', cost = 0, hashStr = ''] = this.userRecord.password.split('$').filter(key => key)
const algorithm = passwordAlgorithmMap[algorithmKey] ? passwordAlgorithmMap[algorithmKey].substring(5) : null
const salt = hashStr.substring(0, Number(cost))
const hash = hashStr.substring(Number(cost))
return {
success: false
algorithm,
salt,
hash
}
}
let refreshPasswordInfo
if (autoRefresh && passwordSecretVersion !== this.getLastestSecret().version) {
refreshPasswordInfo = this.generatePasswordHash({
password
/**
* 生成加密后的密码
* @param {String} password 密码
*/
generatePasswordHash ({ password }) {
if (!password) throw new Error('Invalid password')
const passwordSecret = this._getLastestSecret()
const ext = this._getPasswordExt(passwordSecret)
const { passwordHash, version } = ext.encrypt({
password,
passwordSecret
})
}
return {
success: true,
refreshPasswordInfo
passwordHash,
version
}
}
generatePasswordHash (params = {}) {
let {
password,
passwordSecret,
passwordSecretVersion
} = params
if (getType(password) !== 'string') {
throw new Error('Invalid password')
/**
* 密码校验
* @param {String} password
* @param {Boolean} autoRefresh
* @return {{refreshPasswordInfo: {version: *, passwordHash: *}, success: boolean}|{success: boolean}}
*/
checkUserPassword ({ password, autoRefresh = true }) {
if (!password) throw new Error('Invalid password')
const { password_secret_version: passwordSecretVersion } = this.userRecord
const passwordSecret = this._getSecretByVersion({
version: passwordSecretVersion
})
const ext = this._getPasswordExt(passwordSecret)
const success = ext.verify({ password, passwordSecret })
if (!success) {
return {
success: false
}
password = password && password.trim()
if (!password) {
throw new Error('Invalid password')
}
if (!passwordSecret) {
const lastestSecret = this.getLastestSecret()
passwordSecret = lastestSecret.value
passwordSecretVersion = lastestSecret.version
let refreshPasswordInfo
if (autoRefresh && passwordSecretVersion !== this._getLastestSecret().version) {
refreshPasswordInfo = this.generatePasswordHash({ password })
}
return {
passwordHash: PasswordHashMethod['hmac-sha1'](password, passwordSecret),
version: passwordSecretVersion
success: true,
refreshPasswordInfo
}
}
}
......
......@@ -5,7 +5,7 @@ const {
ERROR
} = require('../../common/error')
function getQQPlatform() {
function getQQPlatform () {
const platform = this.clientPlatform
switch (platform) {
case 'app':
......@@ -18,7 +18,7 @@ function getQQPlatform() {
}
}
async function saveQQUserKey({
async function saveQQUserKey ({
openid,
sessionKey, // QQ小程序用户sessionKey
accessToken, // App端QQ用户accessToken
......@@ -26,7 +26,7 @@ async function saveQQUserKey({
} = {}) {
// 微信公众平台、开放平台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 appId = this.getUniversalClientInfo().appId
const qqPlatform = getQQPlatform.call(this)
const keyObj = {
dcloudAppid: appId,
......@@ -45,9 +45,9 @@ async function saveQQUserKey({
await this.uniOpenBridge.setUserAccessToken(keyObj, {
access_token: accessToken,
access_token_expired: accessTokenExpired
}, accessTokenExpired ?
Math.floor((accessTokenExpired - Date.now()) / 1000) :
30 * 24 * 60 * 60
}, accessTokenExpired
? Math.floor((accessTokenExpired - Date.now()) / 1000)
: 30 * 24 * 60 * 60
)
break
default:
......@@ -55,7 +55,7 @@ async function saveQQUserKey({
}
}
function generateQQCache({
function generateQQCache ({
sessionKey, // QQ小程序用户sessionKey
accessToken, // App端QQ用户accessToken
accessTokenExpired // App端QQ用户accessToken过期时间
......@@ -84,11 +84,11 @@ function generateQQCache({
}
}
function getQQOpenid({
function getQQOpenid ({
userRecord
} = {}) {
const qqPlatform = getQQPlatform.call(this)
const appId = this.getClientInfo().appId
const appId = this.getUniversalClientInfo().appId
const qqOpenidObj = userRecord.qq_openid
if (!qqOpenidObj) {
return
......@@ -96,7 +96,7 @@ function getQQOpenid({
return qqOpenidObj[`${qqPlatform}_${appId}`] || qqOpenidObj[qqPlatform]
}
async function getQQCacheFallback({
async function getQQCacheFallback ({
userRecord,
key
} = {}) {
......@@ -109,13 +109,13 @@ async function getQQCacheFallback({
return qqCache && qqCache[key]
}
async function getQQCache({
async function getQQCache ({
uid,
userRecord,
key
} = {}) {
const qqPlatform = getQQPlatform.call(this)
const appId = this.getClientInfo().appId
const appId = this.getUniversalClientInfo().appId
if (!userRecord) {
const getUserRes = await userCollection.doc(uid).get()
......
......@@ -18,13 +18,13 @@ const {
const PasswordUtils = require('./password')
const merge = require('lodash.merge')
async function realPreRegister(params = {}) {
async function realPreRegister (params = {}) {
const {
user
} = params
const userMatched = await findUser({
userQuery: user,
authorizedApp: this.getClientInfo().appId
authorizedApp: this.getUniversalClientInfo().appId
})
if (userMatched.length > 0) {
throw {
......@@ -33,7 +33,7 @@ async function realPreRegister(params = {}) {
}
}
async function preRegister(params = {}) {
async function preRegister (params = {}) {
try {
await realPreRegister.call(this, params)
} catch (error) {
......@@ -45,7 +45,7 @@ async function preRegister(params = {}) {
}
}
async function preRegisterWithPassword(params = {}) {
async function preRegisterWithPassword (params = {}) {
const {
user,
password
......@@ -54,6 +54,7 @@ async function preRegisterWithPassword(params = {}) {
user
})
const passwordUtils = new PasswordUtils({
clientInfo: this.getUniversalClientInfo(),
passwordSecret: this.config.passwordSecret
})
const {
......@@ -72,7 +73,7 @@ async function preRegisterWithPassword(params = {}) {
}
}
async function thirdPartyRegister({
async function thirdPartyRegister ({
user = {}
} = {}) {
return {
......@@ -81,7 +82,7 @@ async function thirdPartyRegister({
}
}
async function postRegister(params = {}) {
async function postRegister (params = {}) {
const {
user,
extraData = {},
......@@ -98,7 +99,7 @@ async function postRegister(params = {}) {
clientIP,
osName,
uniIdToken
} = this.getClientInfo()
} = this.getUniversalClientInfo()
merge(user, extraData)
......@@ -162,7 +163,7 @@ async function postRegister(params = {}) {
if (beforeRegister) {
userRecord = await beforeRegister({
userRecord,
clientInfo: this.getClientInfo()
clientInfo: this.getUniversalClientInfo()
})
}
......
......@@ -29,7 +29,7 @@ async function preBind ({
} = {}) {
const userMatched = await findUser({
userQuery: bindAccount,
authorizedApp: this.getClientInfo().appId
authorizedApp: this.getUniversalClientInfo().appId
})
if (userMatched.length > 0) {
await this.middleware.uniIdLog({
......
......@@ -17,7 +17,7 @@ async function realPreUnifiedLogin (params = {}) {
user,
type
} = params
const appId = this.getClientInfo().appId
const appId = this.getUniversalClientInfo().appId
const userMatched = await findUser({
userQuery: user,
authorizedApp: appId
......
......@@ -13,7 +13,7 @@ async function getPhoneNumber ({
}
return uniCloud.getPhoneNumber({
provider: 'univerify',
appid: this.getClientInfo().appId,
appid: this.getUniversalClientInfo().appId,
apiKey: univerifyConfig.apiKey,
apiSecret: univerifyConfig.apiSecret,
// eslint-disable-next-line camelcase
......
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
......@@ -23,7 +23,7 @@ async function setVerifyCode ({
scene,
code: code || getVerifyCode(),
state: 0,
ip: this.getClientInfo().clientIP,
ip: this.getUniversalClientInfo().clientIP,
created_date: now,
expired_date: now + expiresIn * 1000
}
......
......@@ -5,6 +5,12 @@ const {
const {
ERROR
} = require('../../common/error')
const {
getRedisEnable
} = require('./utils')
const {
openDataCollection
} = require('../../common/constants')
function decryptWeixinData ({
encryptedData,
......@@ -33,7 +39,7 @@ function decryptWeixinData ({
function getWeixinPlatform () {
const platform = this.clientPlatform
const userAgent = this.getClientInfo().userAgent
const userAgent = this.getUniversalClientInfo().userAgent
switch (platform) {
case 'app':
case 'app-plus':
......@@ -58,7 +64,7 @@ async function saveWeixinUserKey ({
// 微信公众平台、开放平台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 appId = this.getUniversalClientInfo().appId
const weixinPlatform = getWeixinPlatform.call(this)
const keyObj = {
dcloudAppid: appId,
......@@ -85,6 +91,35 @@ async function saveWeixinUserKey ({
}
}
async function saveSecureNetworkCache ({
code,
openid,
unionid,
sessionKey
}) {
const {
appId
} = this.getUniversalClientInfo()
const key = `uni-id:${appId}:weixin-mp:code:${code}:secure-network-cache`
const value = JSON.stringify({
openid,
unionid,
session_key: sessionKey
})
// 此处存储的是code的缓存,有效期两天即可
const expiredSeconds = 2 * 24 * 60 * 60
await openDataCollection.doc(key).set({
value,
expired: Date.now() + expiredSeconds * 1000
})
const isRedisEnable = getRedisEnable()
if (isRedisEnable) {
const redis = uniCloud.redis()
await redis.set(key, value, 'EX', expiredSeconds)
}
}
function generateWeixinCache ({
sessionKey, // 微信小程序用户sessionKey
accessToken, // App端微信用户accessToken
......@@ -122,7 +157,7 @@ function getWeixinOpenid ({
userRecord
} = {}) {
const weixinPlatform = getWeixinPlatform.call(this)
const appId = this.getClientInfo().appId
const appId = this.getUniversalClientInfo().appId
const wxOpenidObj = userRecord.wx_openid
if (!wxOpenidObj) {
return
......@@ -149,7 +184,7 @@ async function getWeixinCache ({
key
} = {}) {
const weixinPlatform = getWeixinPlatform.call(this)
const appId = this.getClientInfo().appId
const appId = this.getUniversalClientInfo().appId
if (!userRecord) {
const getUserRes = await userCollection.doc(uid).get()
userRecord = getUserRes.data[0]
......@@ -179,7 +214,7 @@ async function getWeixinCache ({
async function getWeixinAccessToken () {
const weixinPlatform = getWeixinPlatform.call(this)
const appId = this.getClientInfo().appId
const appId = this.getUniversalClientInfo().appId
const cache = await this.uniOpenBridge.getAccessToken({
dcloudAppid: appId,
......@@ -194,5 +229,6 @@ module.exports = {
generateWeixinCache,
getWeixinCache,
saveWeixinUserKey,
getWeixinAccessToken
getWeixinAccessToken,
saveSecureNetworkCache
}
......@@ -2,7 +2,7 @@ module.exports = async function () {
if (this.authInfo) { // 多次执行auth时如果第一次成功后续不再执行
return
}
const token = this.getUniIdToken()
const token = this.getUniversalUniIdToken()
const payload = await this.uniIdCommon.checkToken(token)
if (payload.errCode) {
throw payload
......
......@@ -19,7 +19,7 @@ module.exports = async function ({
clientIP,
deviceId,
userAgent
} = this.getClientInfo()
} = this.getUniversalClientInfo()
const logData = {
appid: appId,
device_id: deviceId,
......
......@@ -79,7 +79,7 @@ module.exports = async function (params = {}) {
userQuery: {
email
},
authorizedApp: [this.getClientInfo().appId]
authorizedApp: [this.getUniversalClientInfo().appId]
})
if (userMatched.length === 0) {
throw {
......@@ -95,6 +95,7 @@ module.exports = async function (params = {}) {
passwordHash,
version
} = new PasswordUtils({
clientInfo: this.getUniversalClientInfo(),
passwordSecret: this.config.passwordSecret
}).generatePasswordHash({
password
......
......@@ -79,7 +79,7 @@ module.exports = async function (params = {}) {
userQuery: {
mobile
},
authorizedApp: [this.getClientInfo().appId]
authorizedApp: [this.getUniversalClientInfo().appId]
})
if (userMatched.length === 0) {
throw {
......@@ -95,6 +95,7 @@ module.exports = async function (params = {}) {
passwordHash,
version
} = new PasswordUtils({
clientInfo: this.getUniversalClientInfo(),
passwordSecret: this.config.passwordSecret
}).generatePasswordHash({
password
......
......@@ -32,16 +32,18 @@ module.exports = async function (params = {}) {
newPassword
} = params
const passwordUtils = new PasswordUtils({
userRecord,
clientInfo: this.getUniversalClientInfo(),
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
......
......@@ -83,6 +83,7 @@ module.exports = async function (params = {}) {
}
}
const passwordUtils = new PasswordUtils({
clientInfo: this.getUniversalClientInfo(),
passwordSecret: this.config.passwordSecret
})
const {
......
......@@ -107,6 +107,7 @@ module.exports = async function (params = {}) {
if (password) {
const passwordUtils = new PasswordUtils({
clientInfo: this.getUniversalClientInfo(),
passwordSecret: this.config.passwordSecret
})
const {
......
......@@ -56,7 +56,7 @@ module.exports = async function (params = {}) {
} = params
const {
appId
} = this.getClientInfo()
} = this.getUniversalClientInfo()
const qqApi = initQQ.call(this)
const qqPlatform = getQQPlatform.call(this)
let apiName
......
......@@ -2,10 +2,7 @@ const {
initWeixin
} = require('../../lib/third-party/index')
const {
getWeixinPlatform,
getWeixinAccessToken,
generateWeixinCache,
saveWeixinUserKey
getWeixinAccessToken
} = require('../../lib/utils/weixin')
const {
ERROR
......
......@@ -11,7 +11,8 @@ const {
const {
generateWeixinCache,
getWeixinPlatform,
saveWeixinUserKey
saveWeixinUserKey,
saveSecureNetworkCache
} = require('../../lib/utils/weixin')
const {
LOG_TYPE
......@@ -37,11 +38,13 @@ module.exports = async function (params = {}) {
this.middleware.validate(params, schema)
const {
code,
inviteCode
inviteCode,
// 内部参数,暂不暴露
secureNetworkCache = false
} = params
const {
appId
} = this.getClientInfo()
} = this.getUniversalClientInfo()
const weixinApi = initWeixin.call(this)
const weixinPlatform = getWeixinPlatform.call(this)
let apiName
......@@ -81,6 +84,18 @@ module.exports = async function (params = {}) {
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
......
......@@ -38,7 +38,7 @@ module.exports = async function (params = {}) {
}).limit(1).get()
if (getAdminRes.data.length > 0) {
const [admin] = getAdminRes.data
const appId = this.getClientInfo().appId
const appId = this.getUniversalClientInfo().appId
if (!admin.dcloud_appid || (admin.dcloud_appid && admin.dcloud_appid.includes(appId))) {
return {
......
......@@ -49,7 +49,7 @@ module.exports = async function (params = {}) {
accessTokenExpired
} = params
const qqPlatform = getQQPlatform.call(this)
const appId = this.getClientInfo().appId
const appId = this.getUniversalClientInfo().appId
const qqApi = initQQ.call(this)
const clientPlatform = this.clientPlatform
const apiName = clientPlatform === 'mp-qq' ? 'code2Session' : 'getOpenidByToken'
......@@ -78,7 +78,7 @@ module.exports = async function (params = {}) {
const bindAccount = {
qq_openid: {
[clientPlatform]: openid
[qqPlatform]: openid
},
qq_unionid: unionid
}
......
......@@ -34,7 +34,7 @@ module.exports = async function (params = {}) {
code
} = params
const weixinPlatform = getWeixinPlatform.call(this)
const appId = this.getClientInfo().appId
const appId = this.getUniversalClientInfo().appId
const weixinApi = initWeixin.call(this)
const clientPlatform = this.clientPlatform
......@@ -64,7 +64,7 @@ module.exports = async function (params = {}) {
const bindAccount = {
wx_openid: {
[clientPlatform]: openid
[weixinPlatform]: openid
},
wx_unionid: unionid
}
......
......@@ -16,7 +16,7 @@ const {
*/
module.exports = async function () {
const { uid } = this.authInfo
const { appId } = this.getClientInfo()
const { appId } = this.getUniversalClientInfo()
const qqPlatform = getQQPlatform.call(this)
await preUnBind.call(this, {
......
module.exports = {
refreshToken: require('./refresh-token'),
setPushCid: require('./set-push-cid')
setPushCid: require('./set-push-cid'),
secureNetworkHandshakeByWeixin: require('./secure-network-handshake-by-weixin')
}
......@@ -7,7 +7,7 @@ module.exports = async function () {
token,
tokenExpired
} = await this.uniIdCommon.refreshToken({
token: this.getUniIdToken()
token: this.getUniversalUniIdToken()
})
return {
errCode: 0,
......
const {
ERROR
} = require('../../common/error')
const {
initWeixin
} = require('../../lib/third-party/index')
const {
saveWeixinUserKey,
saveSecureNetworkCache
} = require('../../lib/utils/weixin')
const loginByWeixin = require('../login/login-by-weixin')
/**
* 微信安全网络握手
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#set-push-cid
* @param {object} params
* @param {string} params.code 微信登录返回的code
* @param {boolean} params.callLoginByWeixin 是否同时调用一次微信登录
* @returns
*/
module.exports = async function (params = {}) {
const schema = {
code: 'string',
callLoginByWeixin: {
type: 'boolean',
required: false
}
}
this.middleware.validate(params, schema)
let platform = this.clientPlatform
if (platform !== 'mp-weixin') {
throw new Error(`[secureNetworkHandshake] platform ${platform} is not supported`)
}
const {
code,
callLoginByWeixin = false
} = params
if (callLoginByWeixin) {
return loginByWeixin.call(this, {
code,
secureNetworkCache: true
})
}
const weixinApi = initWeixin.call(this)
let getWeixinAccountResult
try {
getWeixinAccountResult = await weixinApi.code2Session(code)
} catch (error) {
console.error(error)
throw {
errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED
}
}
const {
openid,
unionid,
sessionKey // 微信小程序用户sessionKey
} = getWeixinAccountResult
await saveSecureNetworkCache.call(this, {
code,
openid,
unionid,
sessionKey
})
await saveWeixinUserKey.call(this, {
openid,
sessionKey
})
return {
errCode: 0
}
}
......@@ -25,7 +25,7 @@ async function setOpendbDevice ({
screenHeight,
romName,
romVersion
} = this.getClientInfo()
} = this.getUniversalClientInfo()
const platform = this.clientPlatform
const now = Date.now()
......@@ -80,7 +80,7 @@ module.exports = async function (params = {}) {
deviceId,
appId,
osName
} = this.getClientInfo()
} = this.getUniversalClientInfo()
let platform = this.clientPlatform
if (platform === 'app') {
platform += osName
......
......@@ -18,7 +18,7 @@ module.exports = async function (params = {}) {
}
this.middleware.validate(params, schema)
const deviceId = this.getClientInfo().deviceId
const deviceId = this.getUniversalClientInfo().deviceId
const {
scene
} = params
......
......@@ -18,7 +18,7 @@ module.exports = async function (params = {}) {
}
this.middleware.validate(params, schema)
const deviceId = this.getClientInfo().deviceId
const deviceId = this.getUniversalClientInfo().deviceId
const {
scene
} = params
......
{
"name": "uni-id-co",
"version": "1.0.26",
"version": "1.0.30",
"description": "",
"main": "index.js",
"keywords": [],
......@@ -14,6 +14,10 @@
"uni-open-bridge-common": "file:../../../../uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common"
},
"extensions": {
"uni-cloud-sms": {}
"uni-cloud-sms": {},
"uni-cloud-redis": {}
},
"cloudfunction-config": {
"keepRunningAfterReturn": false
}
}
## 1.2.2(2022-11-11)
- uni-list 新增属性 render-reverse 详情参考:[https://uniapp.dcloud.net.cn/component/list.html](https://uniapp.dcloud.net.cn/component/list.html)
- uni-list-chat note属性 支持:“草稿”字样 加红显示 详情参考uni-im:[https://ext.dcloud.net.cn/plugin?name=uni-im](https://ext.dcloud.net.cn/plugin?name=uni-im)
- uni-list-item 新增属性 customStyle 支持设置padding、backgroundColor
## 1.2.1(2022-03-30)
- 删除无用文件
## 1.2.0(2021-11-23)
......
......@@ -24,7 +24,10 @@
<view class="uni-list-chat__content">
<view class="uni-list-chat__content-main">
<text class="uni-list-chat__content-title uni-ellipsis">{{ title }}</text>
<text class="uni-list-chat__content-note uni-ellipsis">{{ note }}</text>
<view style="flex-direction: row;">
<text class="draft" v-if="isDraft">[草稿]</text>
<text class="uni-list-chat__content-note uni-ellipsis">{{isDraft?note.slice(14,-1):note}}</text>
</view>
</view>
<view class="uni-list-chat__content-extra">
<slot>
......@@ -121,6 +124,9 @@
},
// inject: ['list'],
computed: {
isDraft(){
return this.note.slice(0,14) == '[uni-im-draft]'
},
isSingle() {
if (this.badgeText === 'dot') {
return 'uni-badge--dot';
......@@ -445,13 +451,20 @@
overflow: hidden;
}
.uni-list-chat__content-note {
.draft ,.uni-list-chat__content-note {
margin-top: 3px;
color: $note-color;
font-size: $note-size;
font-weight: $title-weight;
overflow: hidden;
}
.draft{
color: #eb3a41;
/* #ifndef APP-NVUE */
flex-shrink: 0;
/* #endif */
padding-right: 3px;
}
.uni-list-chat__content-extra {
/* #ifndef APP-NVUE */
......
<template>
<!-- #ifdef APP-NVUE -->
<cell>
<cell keep-scroll-position>
<!-- #endif -->
<view :class="{ 'uni-list-item--disabled': disabled }"
<view :class="{ 'uni-list-item--disabled': disabled }" :style="{'background-color':customStyle.backgroundColor}"
:hover-class="(!clickable && !link) || disabled || showSwitch ? '' : 'uni-list-item--hover'"
class="uni-list-item" @click="onClick">
<view v-if="!isFirstChild" class="border--left" :class="{ 'uni-list--border': border }"></view>
<view class="uni-list-item__container"
:class="{ 'container--right': showArrow || link, 'flex--direction': direction === 'column' }">
:class="{ 'container--right': showArrow || link, 'flex--direction': direction === 'column'}"
:style="{padding:customStyle.padding}">
<slot name="header">
<view class="uni-list-item__header">
<view v-if="thumb" class="uni-list-item__icon">
......@@ -96,7 +96,7 @@
default: ''
},
ellipsis: {
type: [Number,String],
type: [Number, String],
default: 0
},
disabled: {
......@@ -139,7 +139,7 @@
type: String,
default: 'success'
},
badgeStyle:{
badgeStyle: {
type: Object,
default () {
return {}
......@@ -174,6 +174,15 @@
border: {
type: Boolean,
default: true
},
customStyle: {
type: Object,
default () {
return {
padding: '',
backgroundColor: '#FFFFFF'
}
}
}
},
// inject: ['list'],
......@@ -275,6 +284,7 @@
$uni-bg-color-hover:#f1f1f1;
$uni-text-color-grey:#999;
$list-item-pd: $uni-spacing-col-lg $uni-spacing-row-lg;
.uni-list-item {
/* #ifndef APP-NVUE */
display: flex;
......@@ -289,12 +299,15 @@
cursor: pointer;
/* #endif */
}
.uni-list-item--disabled {
opacity: 0.3;
}
.uni-list-item--hover {
background-color: $uni-bg-color-hover;
}
.uni-list-item__container {
position: relative;
/* #ifndef APP-NVUE */
......@@ -307,9 +320,11 @@
overflow: hidden;
// align-items: center;
}
.container--right {
padding-right: 0;
}
// .border--left {
// margin-left: $uni-spacing-row-lg;
// }
......@@ -324,6 +339,7 @@
border-top-width: 0.5px;
/* #endif */
}
/* #ifndef APP-NVUE */
.uni-list--border:after {
position: absolute;
......@@ -336,6 +352,7 @@
transform: scaleY(0.5);
background-color: $uni-border-color;
}
/* #endif */
.uni-list-item__content {
/* #ifndef APP-NVUE */
......@@ -349,20 +366,24 @@
justify-content: space-between;
overflow: hidden;
}
.uni-list-item__content--center {
justify-content: center;
}
.uni-list-item__content-title {
font-size: $uni-font-size-base;
color: #3b4144;
overflow: hidden;
}
.uni-list-item__content-note {
margin-top: 6rpx;
color: $uni-text-color-grey;
font-size: $uni-font-size-sm;
overflow: hidden;
}
.uni-list-item__extra {
// width: 25%;
/* #ifndef APP-NVUE */
......@@ -372,6 +393,7 @@
justify-content: flex-end;
align-items: center;
}
.uni-list-item__header {
/* #ifndef APP-NVUE */
display: flex;
......@@ -379,12 +401,14 @@
flex-direction: row;
align-items: center;
}
.uni-list-item__icon {
margin-right: 18rpx;
flex-direction: row;
justify-content: center;
align-items: center;
}
.uni-list-item__icon-img {
/* #ifndef APP-NVUE */
display: block;
......@@ -393,6 +417,7 @@
width: $uni-img-size-base;
margin-right: 10px;
}
.uni-icon-wrapper {
/* #ifndef APP-NVUE */
display: flex;
......@@ -400,33 +425,40 @@
align-items: center;
padding: 0 10px;
}
.flex--direction {
flex-direction: column;
/* #ifndef APP-NVUE */
align-items: initial;
/* #endif */
}
.flex--justify {
/* #ifndef APP-NVUE */
justify-content: initial;
/* #endif */
}
.uni-list--lg {
height: $uni-img-size-lg;
width: $uni-img-size-lg;
}
.uni-list--base {
height: $uni-img-size-base;
width: $uni-img-size-base;
}
.uni-list--sm {
height: $uni-img-size-sm;
width: $uni-img-size-sm;
}
.uni-list-item__extra-text {
color: $uni-text-color-grey;
font-size: $uni-font-size-sm;
}
.uni-ellipsis-1 {
/* #ifndef APP-NVUE */
overflow: hidden;
......@@ -435,9 +467,10 @@
/* #endif */
/* #ifdef APP-NVUE */
lines: 1;
text-overflow:ellipsis;
text-overflow: ellipsis;
/* #endif */
}
.uni-ellipsis-2 {
/* #ifndef APP-NVUE */
overflow: hidden;
......@@ -448,7 +481,7 @@
/* #endif */
/* #ifdef APP-NVUE */
lines: 2;
text-overflow:ellipsis;
text-overflow: ellipsis;
/* #endif */
}
</style>
......@@ -7,18 +7,21 @@
</view>
<!-- #endif -->
<!-- #ifdef APP-NVUE -->
<list class="uni-list" :class="{ 'uni-list--border': border }" :enableBackToTop="enableBackToTop" loadmoreoffset="15"><slot /></list>
<list :bounce="false" :scrollable="true" show-scrollbar :render-reverse="renderReverse" @scroll="scroll" class="uni-list" :class="{ 'uni-list--border': border }" :enableBackToTop="enableBackToTop"
loadmoreoffset="15">
<slot />
</list>
<!-- #endif -->
</template>
<script>
/**
/**
* List 列表
* @description 列表组件
* @tutorial https://ext.dcloud.net.cn/plugin?id=24
* @property {String} border = [true|false] 标题
*/
export default {
export default {
name: 'uniList',
'mp-weixin': {
options: {
......@@ -26,6 +29,10 @@ export default {
}
},
props: {
stackFromEnd:{
type: Boolean,
default:false
},
enableBackToTop: {
type: [Boolean, String],
default: false
......@@ -37,6 +44,10 @@ export default {
border: {
type: Boolean,
default: true
},
renderReverse:{
type: Boolean,
default: false
}
},
// provide() {
......@@ -50,23 +61,27 @@ export default {
methods: {
loadMore(e) {
this.$emit('scrolltolower');
},
scroll(e) {
this.$emit('scroll', e);
}
}
};
};
</script>
<style lang="scss" >
$uni-bg-color:#ffffff;
$uni-border-color:#e5e5e5;
.uni-list {
<style lang="scss">
$uni-bg-color:#ffffff;
$uni-border-color:#e5e5e5;
.uni-list {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
background-color: $uni-bg-color;
position: relative;
flex-direction: column;
}
}
.uni-list--border {
.uni-list--border {
position: relative;
/* #ifdef APP-NVUE */
border-top-color: $uni-border-color;
......@@ -77,11 +92,11 @@ $uni-border-color:#e5e5e5;
border-bottom-width: 0.5px;
/* #endif */
z-index: -1;
}
}
/* #ifndef APP-NVUE */
/* #ifndef APP-NVUE */
.uni-list--border-top {
.uni-list--border-top {
position: absolute;
top: 0;
right: 0;
......@@ -91,9 +106,9 @@ $uni-border-color:#e5e5e5;
transform: scaleY(0.5);
background-color: $uni-border-color;
z-index: 1;
}
}
.uni-list--border-bottom {
.uni-list--border-bottom {
position: absolute;
bottom: 0;
right: 0;
......@@ -102,7 +117,7 @@ $uni-border-color:#e5e5e5;
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
background-color: $uni-border-color;
}
}
/* #endif */
/* #endif */
</style>
{
"id": "uni-list",
"displayName": "uni-list 列表",
"version": "1.2.1",
"version": "1.2.2",
"description": "List 组件 ,帮助使用者快速构建列表。",
"keywords": [
"",
......@@ -18,11 +18,7 @@
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
......@@ -39,7 +35,8 @@
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
"type": "component-vue"
},
"uni_modules": {
"dependencies": [
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册