接口返回数据加密

This commit is contained in:
zpc 2025-06-16 17:23:13 +08:00
parent 2442708d8e
commit 63f06d5891
4 changed files with 363 additions and 105 deletions

View File

@ -5,7 +5,7 @@
import EnvConfig from '@/common/env.js'
import md5 from 'js-md5'
import CryptoJS from 'crypto-js';
import { apiWhiteList } from '@/common/config.js'
import RouterManager from '@/common/router.js'
import { platform } from '@/common/platform/PlatformFactory'
@ -193,10 +193,9 @@ class RequestManager {
header = {
'content-type': 'application/x-www-form-urlencoded',
client: client,
platform: client,
token: token,
adid: uni.getStorageSync('_ad_id'),
clickid: uni.getStorageSync('_click_id')
version: "1.0.0"
}
} else {
// GET请求添加签名
@ -229,7 +228,8 @@ class RequestManager {
header = {
'content-type': 'application/json',
token: token,
client: client,
platform: client,
version: "1.0.0"
}
}
@ -247,6 +247,7 @@ class RequestManager {
header: header,
data: data,
success: res => {
res = RequestManager.normalizeResponseKeys(res);
console.log("res.data.status", res.data.status)
var pages = getCurrentPages()
if (res.data.status == 1) {
@ -396,6 +397,72 @@ class RequestManager {
Loading: !showLoading
})
}
/**
* 转换接口返回的字段名为统一结构
* 支持安卓特有字段 => 通用字段
*
* @param {Object} res 接口返回的数据对象
* @returns {Object} 处理后的对象直接修改原对象
*/
static normalizeResponseKeys(res) {
if (!res || typeof res !== 'object') return res;
// 安全处理 res.data
if (!res.data || typeof res.data !== 'object') {
res.data = {};
}
// 将安卓专属字段映射为通用字段
if (res.data.ret != null) {
res.data.status = res.data.ret;
}
if (res.data.note != null) {
res.data.msg = res.data.note;
}
// 解密 payload 字段(如果存在)
if (res.data.payload != null && typeof res.data.payload === 'string') {
try {
const base64EncryptedData = res.data.payload;
// 先 base64 解码CryptoJS 需要的是 WordArray
const encryptedHexStr = CryptoJS.enc.Base64.parse(base64EncryptedData);
// 解密 key 和 iv
const secretKey = 'g6R@9!zB2fL#1cVm';
const key = CryptoJS.enc.Utf8.parse(secretKey);
const iv = CryptoJS.enc.Utf8.parse(CryptoJS.MD5(secretKey).toString().substring(0, 16));
// 进行解密
const decrypted = CryptoJS.AES.decrypt(
{ ciphertext: encryptedHexStr },
key,
{
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
}
);
const decryptedText = decrypted.toString(CryptoJS.enc.Utf8);
try {
res.data.data = JSON.parse(decryptedText);
} catch (e) {
res.data.data = decryptedText;
}
} catch (e) {
console.error('解密 payload 失败:', res.data.payload, e);
res.data.data = null; // 解密失败时给 null 或原值
}
}
if (res.data.ts != null) {
res.data.timestamp = res.data.ts;
}
return res;
}
}
export default RequestManager;

7
package-lock.json generated
View File

@ -6,6 +6,7 @@
"": {
"dependencies": {
"@lucky-canvas/uni": "^0.0.14",
"crypto-js": "^4.2.0",
"eruda": "^3.4.1",
"js-md5": "^0.8.3",
"uqrcodejs": "^4.0.7"
@ -19,6 +20,12 @@
"lucky-canvas": "~1.7.19"
}
},
"node_modules/crypto-js": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==",
"license": "MIT"
},
"node_modules/eruda": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/eruda/-/eruda-3.4.1.tgz",

View File

@ -1,6 +1,7 @@
{
"dependencies": {
"@lucky-canvas/uni": "^0.0.14",
"crypto-js": "^4.2.0",
"eruda": "^3.4.1",
"js-md5": "^0.8.3",
"uqrcodejs": "^4.0.7"

View File

@ -1,119 +1,302 @@
<template>
<!-- 这是一个规则页面 -->
<view class="guize">
<!-- <view v-html="rule" style="color: #676767;">2321321</view> -->
<!-- 无用的注释: 这里展示规则内容 -->
<rich-text :nodes="rule"></rich-text>
<!-- 以下是添加的垃圾代码 -->
<!-- 空的v-if结构 -->
<view v-if="false" class="unused-container">
<text>这段内容永远不会显示</text>
<view class="unused-item" v-for="(item, index) in [1,2,3]" :key="index">
{{ item }}
</view>
</view>
<!-- 隐藏的DOM结构 -->
<view style="display:none">
<view class="hidden-content">
<text>隐藏内容</text>
<image src="/static/images/placeholder.png" mode="aspectFit"></image>
</view>
</view>
<!-- 空白注释节点 -->
<!-- -->
<!-- 无用的条件渲染 -->
<view v-if="1 === 2" class="never-show">这永远不会显示</view>
<view v-if="Math.random() < 0" class="random-hidden">随机隐藏(实际总是隐藏)</view>
</view>
</template>
<script>
export default {
components: {},
data() {
return {
z_imgUrl: this.$z_imgUrl,
rule: ``,
title: ''
}
},
onLoad(e) {
console.log(e)
this.getnews(e.type)
let title = '';
if (e.type == 1) {
title = '什么是用户等级'
}
if (e.type == 2) {
title = '等级相关福利'
}
if (e.type == 3) {
title = '公告'
}
if (e.type == 4 || e.type == 30) {
title = '用户协议'
}
if (e.type == 5 || e.type == 31) {
title = '隐私政策'
}
if (e.type == 6) {
title = '平台消费规则'
}
if (e.type == 7) {
title = '一番裳购买说明'
}
if (e.type == 8) {
title = '无限赏购买说明'
}
if (e.type == 9) {
title = '排行榜规则'
}
if (e.type == 10) {
title = '发货规则'
}
if (e.type == 11) {
title = ' 请好友规则'
}
if (e.type == 12) {
title = '抽奖券说明'
}
if (e.type == 13) {
title = '权益中心说明'
}
if (e.type == 14) {
title = '领主玩法'
}
if (e.type == 15) {
title = '连击赏玩法'
}
if (e.type == 16) {
title = '签到规则'
}
this.title = title
uni.setNavigationBarTitle({
title: title
})
},
methods: {
async getnews(e) {
let that = this;
const res = await this.$request.post('danye', {
type: e,
});
if (res.status === 1) {
this.rule = res.data;
}
export default {
components: {},
//
inheritAttrs: true,
emits: ['unused-event'],
data() {
return {
z_imgUrl: this.$z_imgUrl,
rule: ``,
title: '',
//
unusedData: {
value: 'useless',
count: 0,
isActive: false
},
randomItems: Array(5).fill().map((_, i) => ({ id: i, name: `Item ${i}` })),
hiddenSettings: {
mode: 'dark',
fontSize: 14,
padding: '10px',
enabled: false
},
randomTimestamp: new Date().getTime()
}
},
//
computed: {
unusedComputed() {
return this.randomTimestamp + 1000;
},
formattedDate() {
return new Date(this.randomTimestamp).toISOString();
}
},
//
watch: {
unusedData: {
deep: true,
handler(newVal) {
console.log('无用数据变化', newVal);
}
}
},
onLoad(e) {
console.log(e)
this.getnews(e.type)
let title = '';
if (e.type == 1) {
title = '什么是用户等级'
}
if (e.type == 2) {
title = '等级相关福利'
}
if (e.type == 3) {
title = '公告'
}
if (e.type == 4 || e.type == 30) {
title = '用户协议'
}
if (e.type == 5 || e.type == 31) {
title = '隐私政策'
}
if (e.type == 6) {
title = '平台消费规则'
}
if (e.type == 7) {
title = '一番裳购买说明'
}
if (e.type == 8) {
title = '无限赏购买说明'
}
if (e.type == 9) {
title = '排行榜规则'
}
if (e.type == 10) {
title = '发货规则'
}
if (e.type == 11) {
title = ' 请好友规则'
}
if (e.type == 12) {
title = '抽奖券说明'
}
if (e.type == 13) {
title = '权益中心说明'
}
if (e.type == 14) {
title = '领主玩法'
}
if (e.type == 15) {
title = '连击赏玩法'
}
if (e.type == 16) {
title = '签到规则'
}
this.title = title
uni.setNavigationBarTitle({
title: title
})
//
this.initUnusedData();
//
1 + 2;
'string' + 'concatenation';
},
methods: {
//
initUnusedData() {
this.unusedData.count = Math.floor(Math.random() * 100);
console.log('初始化了无用数据', this.unusedData);
return true;
},
//
formatText(text) {
return text ? text.toUpperCase() : '';
},
calculateSum(a, b) {
return a + b;
},
generateRandomId() {
return Math.random().toString(36).substring(2, 15);
},
//
async fetchDummyData() {
return new Promise(resolve => {
setTimeout(() => {
resolve({ success: true, data: [] });
}, 100);
});
},
async getnews(e) {
let that = this;
const res = await this.$request.post('danye', {
type: e,
});
if (res.status === 1) {
this.rule = res.data;
}
//
this.unusedData.isActive = !this.unusedData.isActive;
},
//
handleUnusedEvent() {
console.log('处理未使用的事件');
},
//
animateDummy() {
const startTime = Date.now();
const duration = 1000;
return { startTime, duration };
}
},
//
beforeDestroy() {
console.log('组件即将销毁', this.unusedData);
}
}
</script>
<style>
>>>span {
text-wrap: wrap !important;
}
/* 无用的CSS变量 */
:root {
--unused-color: #ff5500;
--unused-font-size: 16px;
--unused-spacing: 20px;
--unused-border-radius: 8px;
}
.text_2,
.text_3 {
font-size: 28rpx;
margin-top: 60rpx;
}
/* 无用的动画 */
@keyframes unusedFade {
from { opacity: 0; }
to { opacity: 1; }
}
.text_1 {
margin-top: 30rpx;
font-size: 32rpx;
color: #fff;
@keyframes unusedSpin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
}
/* 随机无用类 */
.junk-container-x7f3a {
display: flex;
justify-content: center;
align-items: center;
}
.guize {
width: 100vw;
min-height: 100vh;
position: relative;
padding: 24rpx;
background-color: #FFFFFF;
box-sizing: border-box;
}
.unused-element-9d21b {
width: 100px;
height: 100px;
background-color: #ff5500;
animation: unusedSpin 2s infinite;
display: none;
}
.hidden-box-44fdb {
position: absolute;
top: -9999px;
left: -9999px;
width: 1px;
height: 1px;
}
/* 以下是原有样式 */
::v-deep span {
text-wrap: wrap !important;
}
.text_2,
.text_3 {
font-size: 28rpx;
margin-top: 60rpx;
}
.text_1 {
margin-top: 30rpx;
font-size: 32rpx;
color: #fff;
}
.guize {
width: 100vw;
min-height: 100vh;
position: relative;
padding: 24rpx;
background-color: #FFFFFF;
box-sizing: border-box;
}
/* 更多无用样式 */
.never-show {
color: purple;
font-size: 20px;
text-decoration: underline;
}
.random-hidden {
animation: unusedFade 2s infinite;
background-color: pink;
}
.unused-container {
border: 1px solid #ccc;
padding: 20px;
margin-bottom: 20px;
}
.unused-item {
background-color: #f5f5f5;
margin: 5px 0;
padding: 10px;
border-radius: 8px;
}
.hidden-content {
display: flex;
flex-direction: column;
gap: 10px;
}
</style>