const crypto = require('crypto') const { userCollection } = require('../../common/constants') const { ERROR } = require('../../common/error') const { getRedisEnable } = require('./utils') const { openDataCollection } = require('../../common/constants') function decryptWeixinData ({ encryptedData, sessionKey, iv } = {}) { const oauthConfig = this.configUtils.getOauthConfig({ provider: 'weixin' }) const decipher = crypto.createDecipheriv( 'aes-128-cbc', Buffer.from(sessionKey, 'base64'), Buffer.from(iv, 'base64') ) // 设置自动 padding 为 true,删除填充补位 decipher.setAutoPadding(true) let decoded decoded = decipher.update(encryptedData, 'base64', 'utf8') decoded += decipher.final('utf8') decoded = JSON.parse(decoded) if (decoded.watermark.appid !== oauthConfig.appid) { throw new Error('Invalid wechat appid in decode content') } return decoded } function getWeixinPlatform () { const platform = this.clientPlatform const userAgent = this.getUniversalClientInfo().userAgent switch (platform) { case 'app': case 'app-plus': return 'app' case 'mp-weixin': return 'mp' case 'h5': case 'web': return userAgent.indexOf('MicroMessenger') > -1 ? 'h5' : 'web' default: throw new Error('Unsupported weixin platform') } } async function saveWeixinUserKey ({ openid, sessionKey, // 微信小程序用户sessionKey accessToken, // App端微信用户accessToken refreshToken, // App端微信用户refreshToken accessTokenExpired // App端微信用户accessToken过期时间 } = {}) { // 微信公众平台、开放平台refreshToken有效期均为30天(微信没有在网络请求里面返回30天这个值,务必注意未来可能出现调整,需及时更新此处逻辑)。 // 此前QQ开放平台有调整过accessToken的过期时间:[access_token有效期由90天缩短至30天](https://wiki.connect.qq.com/%E3%80%90qq%E4%BA%92%E8%81%94%E3%80%91access_token%E6%9C%89%E6%95%88%E6%9C%9F%E8%B0%83%E6%95%B4) const appId = this.getUniversalClientInfo().appId const weixinPlatform = getWeixinPlatform.call(this) const keyObj = { dcloudAppid: appId, openid, platform: 'weixin-' + weixinPlatform } switch (weixinPlatform) { case 'mp': await this.uniOpenBridge.setSessionKey(keyObj, { session_key: sessionKey }, 30 * 24 * 60 * 60) break case 'app': case 'h5': case 'web': await this.uniOpenBridge.setUserAccessToken(keyObj, { access_token: accessToken, refresh_token: refreshToken, access_token_expired: accessTokenExpired }, 30 * 24 * 60 * 60) break default: break } } async function saveSecureNetworkCache ({ code, openid, unionid, sessionKey }) { const { appId } = this.getUniversalClientInfo() const key = `uni-id:${appId}:weixin-mp:code:${code}:secure-network-cache` const value = JSON.stringify({ openid, unionid, session_key: sessionKey }) // 此处存储的是code的缓存,设置有效期和token一致 const expiredSeconds = this.config.tokenExpiresIn || 3 * 24 * 60 * 60 await openDataCollection.doc(key).set({ value, expired: Date.now() + expiredSeconds * 1000 }) const isRedisEnable = getRedisEnable() if (isRedisEnable) { const redis = uniCloud.redis() await redis.set(key, value, 'EX', expiredSeconds) } } function generateWeixinCache ({ sessionKey, // 微信小程序用户sessionKey accessToken, // App端微信用户accessToken refreshToken, // App端微信用户refreshToken accessTokenExpired // App端微信用户accessToken过期时间 } = {}) { const platform = getWeixinPlatform.call(this) let cache switch (platform) { case 'app': case 'h5': case 'web': cache = { access_token: accessToken, refresh_token: refreshToken, access_token_expired: accessTokenExpired } break case 'mp': cache = { session_key: sessionKey } break default: throw new Error('Unsupported weixin platform') } return { third_party: { [`${platform}_weixin`]: cache } } } function getWeixinOpenid ({ userRecord } = {}) { const weixinPlatform = getWeixinPlatform.call(this) const appId = this.getUniversalClientInfo().appId const wxOpenidObj = userRecord.wx_openid if (!wxOpenidObj) { return } return wxOpenidObj[`${weixinPlatform}_${appId}`] || wxOpenidObj[weixinPlatform] } async function getWeixinCacheFallback ({ userRecord, key } = {}) { const platform = getWeixinPlatform.call(this) const thirdParty = userRecord && userRecord.third_party if (!thirdParty) { return } const weixinCache = thirdParty[`${platform}_weixin`] return weixinCache && weixinCache[key] } async function getWeixinCache ({ uid, userRecord, key } = {}) { const weixinPlatform = getWeixinPlatform.call(this) const appId = this.getUniversalClientInfo().appId if (!userRecord) { const getUserRes = await userCollection.doc(uid).get() userRecord = getUserRes.data[0] } if (!userRecord) { throw { errCode: ERROR.ACCOUNT_NOT_EXISTS } } const openid = getWeixinOpenid.call(this, { userRecord }) const getCacheMethod = weixinPlatform === 'mp' ? 'getSessionKey' : 'getUserAccessToken' const userKey = await this.uniOpenBridge[getCacheMethod]({ dcloudAppid: appId, platform: 'weixin-' + weixinPlatform, openid }) if (userKey) { return userKey[key] } return getWeixinCacheFallback({ userRecord, key }) } async function getWeixinAccessToken () { const weixinPlatform = getWeixinPlatform.call(this) const appId = this.getUniversalClientInfo().appId const cache = await this.uniOpenBridge.getAccessToken({ dcloudAppid: appId, platform: 'weixin-' + weixinPlatform }) return cache.access_token } module.exports = { decryptWeixinData, getWeixinPlatform, generateWeixinCache, getWeixinCache, saveWeixinUserKey, getWeixinAccessToken, saveSecureNetworkCache }