下载页面增加举报功能

publicsignpoll
youngS 3 years ago
parent 20ac8eadda
commit 479abff102
  1. 1
      fir_client/public/short.html
  2. 222
      fir_client/src/components/FirDownload.vue
  3. 34
      fir_client/src/components/FirLogin.vue
  4. 34
      fir_client/src/components/FirRegist.vue
  5. 32
      fir_client/src/components/FirResetPwd.vue
  6. 370
      fir_client/src/components/ShortDownload.vue
  7. 41
      fir_client/src/components/user/FirUserProfileCertification.vue
  8. 35
      fir_client/src/components/user/FirUserProfileInfo.vue
  9. 26
      fir_client/src/main.short.js
  10. 155
      fir_client/src/restful/download.js
  11. 15
      fir_client/src/restful/index.js
  12. 4
      fir_client/src/utils/index.js
  13. 4
      fir_client/vue.config.js
  14. 2
      fir_ser/admin/views/login.py
  15. 21
      fir_ser/api/models.py
  16. 2
      fir_ser/api/urls.py
  17. 4
      fir_ser/api/utils/TokenManager.py
  18. 6
      fir_ser/api/utils/serializer.py
  19. 6
      fir_ser/api/utils/utils.py
  20. 71
      fir_ser/api/views/login.py
  21. 76
      fir_ser/api/views/report.py
  22. 20
      fir_ser/config.py
  23. 2
      fir_ser/fir_ser/settings.py

@ -5,6 +5,7 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<script src="<%= BASE_URL %>gt.js"></script>
<title>应用下载</title>
</head>
<body>

@ -2,6 +2,74 @@
<el-container class="container">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0">
<el-main style="margin-top: -60px" v-if="report_flag">
<a style="color: #3888fa" @click="report_flag=false">&lt;&nbsp;返回下载页</a>
<el-header style="text-align: center;height: 20px;margin-top: 10px">举报详情</el-header>
<el-form>
<el-form-item>
<span>举报原因</span>
<el-select v-model="report_info.report_type" style="width: 100%">
<el-option v-for="item in report_info_list" :key="item.id" :label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item style="margin-top: -10px">
<span>详细原因</span>
<el-input type="textarea"
:rows="3"
v-model="report_info.report_reason"
placeholder="请详细说明举报原因"></el-input>
</el-form-item>
</el-form>
<el-divider/>
<el-form style="margin-top: -20px">
<el-header style="text-align: center;height: 20px">举报人信息填写</el-header>
<el-form-item>
<span>真实姓名</span>
<el-input v-model="report_info.username" placeholder="请输入您的姓名" clearable></el-input>
</el-form-item>
<el-form-item style="margin-top: -10px">
<span>联系信息</span>
<el-row>
<el-input v-model="report_info.email" :placeholder="`请输入您的${report_info_title}`"
clearable></el-input>
</el-row>
<el-row v-if="captcha.captcha_image" style="margin-top: 10px;margin-bottom: -10px">
<el-col :span="16">
<el-input placeholder="请输入图片验证码" v-model="report_info.authcode" maxlength="6" clearable/>
</el-col>
<el-col :span="8">
<el-image
style="margin:0 4px;border-radius:4px;cursor:pointer;height: 40px"
:src="captcha.captcha_image"
fit="contain" @click="get_auth_code">
</el-image>
</el-col>
</el-row>
<el-row style="margin-top: 10px">
<el-col :span="12">
<el-input v-model="report_info.seicode" prefix-icon="el-icon-mobile"
placeholder="验证码" clearable/>
</el-col>
<el-col :span="12">
<el-button type="info" @click="getphonecode" plain
style="margin:0 4px;border-radius:4px;cursor:pointer;height: 40px;width: 100%">
获取验证码
</el-button>
</el-col>
</el-row>
</el-form-item>
<el-form-item>
<div id="captcha" ref="captcha"></div>
</el-form-item>
<el-button style="width: 100%;height: 60px;" type="primary" plain @click="report_submit">立即举报
</el-button>
</el-form>
</el-main>
<div class="wechat_tip_content" v-if="(agent === 'wxandroid' || agent === 'wxapple') && !wrong">
<div class="mask">
@ -19,7 +87,7 @@
<!-- <span class="pattern right"><img src="@/assets/down_right.png"></span>-->
</div>
<el-container class="out-container " v-if="wxeasytypeflag">
<el-container class="out-container " v-if="wxeasytypeflag && !report_flag">
<div class="main">
<header>
@ -220,7 +288,9 @@
<div class="footer" style="margin-top: 30%;margin-bottom: 8px">
免责声明<br>
本网站仅提供下载托管应用为用户自行上传请甄别应用风险后进行下载
本网站仅提供下载托管应用为用户自行上传请甄别应用风险后进行下载<a class="one-key-report"
@click="get_auth_code(),report_flag=true">举报</a>
</div>
<div v-if="agent!==''">
<div v-if="ad_info.ad_uri" style="margin-bottom: 80px"/>
@ -239,7 +309,7 @@
</el-container>
<div v-else>
<i>
<i v-if="!report_flag">
{{this.currentappinfo.name | formatName}}
</i>
</div>
@ -274,12 +344,37 @@
<script>
import QRCode from 'qrcodejs2'
import {getdownloadurl, getShortAppinfo, gettask} from '@/restful'
import {
getdownloadurl,
getShortAppinfo,
gettask,
getAuthTokenFun,
appReport,
checkEmail,
checkphone,
geetest
} from '@/restful/download'
export default {
name: "FirDownload",
data() {
return {
captcha: {"captcha_image": '', "captcha_key": '', "length": 8},
report_info: {
'username': '',
'report_type': '',
'report_reason': '',
'seicode': '',
'authcode': '',
'email': '',
'auth_token': '',
'act': 'email',
},
report_info_title: '邮箱',
report_info_list: [
{'id': 0, name: '其他'},
],
report_flag: false,
signhelplist: [
{msg: '第一步 允许打开配置描述文件', url: require('@/assets/sign/step1.jpg')},
{msg: '第二步 点击右上角安装按钮', url: require('@/assets/sign/step2.jpg')},
@ -326,6 +421,117 @@
clearTimeout(this.timer);
},
methods: {
report_submit() {
let data = this.report_info;
data['app_id'] = this.currentappinfo.app_id;
if (this.report_info.auth_token && this.report_info.email && this.report_info.seicode) {
appReport(res => {
if (res.code === 1000) {
this.$message.success("信息提交成功,感谢您的支持,即将返回下载页");
// eslint-disable-next-line no-unused-vars
this.timer = setTimeout(data => {
this.report_flag = false;
}, 3000);
} else {
this.$message.error("信息提交失败,请稍后再试 " + res.msg)
}
}, {
'methods': 'POST',
'data': this.report_info
})
} else {
this.$message({
message: '请输入完整的信息',
type: 'warning'
});
}
},
getphonecode() {
if (!this.report_info.username || !this.report_info.report_reason || this.report_info.report_type === '') {
this.$message({
message: '请输入完整的信息',
type: 'warning'
});
return 0
}
if (this.report_info.act === 'email') {
if (!checkEmail(this.report_info.email)) {
this.$message({
message: '请输入正确的邮箱地址',
type: 'warning'
});
return 0
}
}
if (this.report_info.act === 'sms') {
if (!checkphone(this.report_info.email)) {
this.$message({
message: '请输入正确的手机号',
type: 'warning'
});
return 0
}
}
let picode = {
"authcode": this.report_info.authcode,
"captcha_key": this.captcha.captcha_key,
"report": this.currentappinfo.app_id
};
let params = {'act': this.report_info.act, 'target': this.report_info.email, 'ext': picode};
if (this.captcha.geetest) {
geetest(this, this.report_info.email, params, (n_params) => {
this.do_get_auth_token(n_params);
})
} else {
this.do_get_auth_token(params);
}
},
do_get_auth_token(params) {
getAuthTokenFun(data => {
if (data.code === 1000) {
this.$notify({
title: '验证码',
message: '验证码已经发送您',
type: 'success'
});
this.report_info.auth_token = data.data.auth_token;
} else {
this.$message({
message: data.msg,
type: 'error'
});
}
}, {"methods": 'POST', 'data': params})
},
get_auth_code() {
appReport(data => {
if (data.code === 1000) {
let jdata = data.data;
if (jdata.enable) {
this.captcha = data.data;
if (data.data.s_list) {
this.report_info_list = data.data.s_list;
}
if (jdata.report_type && jdata.report_type.sms) {
this.report_info_title = '手机号';
this.report_info.act = 'sms'
} else if (jdata.report_type && jdata.report_type.email) {
this.report_info_title = '邮箱';
this.report_info.act = 'email'
}
this.report_info.seicode = '';
this.report_info.auth_token = '';
return
}
}
this.$message.warning('暂未开通举报功能');
this.report_flag = false;
}, {
"methods": "GET",
"data": {}
});
},
show_err_msg(msg) {
this.msg = msg;
this.$message({
@ -443,7 +649,6 @@
this.downloadurl = res.data.download_url;
}
}
window.location.href = this.downloadurl;
} else if (res.code === 1009) {
this.isdownload = false;
@ -714,6 +919,13 @@
</script>
<style scoped>
.one-key-report {
color: #fff;
background-color: #32B2A7;
padding: 1px 5px;
border-radius: 15px;
}
.app_bottom_fixed {
position: fixed;
bottom: 0;

@ -32,7 +32,7 @@
</el-tabs>
<el-form-item v-if="is_cptch">
<el-form-item v-if="is_captcha">
<el-input v-model="form.password" prefix-icon="el-icon-lock" placeholder="密码"
@keyup.enter.native="onSubmit"
show-password clearable/>
@ -41,7 +41,7 @@
<el-input v-model="form.password" prefix-icon="el-icon-lock" placeholder="密码"
show-password clearable/>
</el-form-item>
<el-form-item style="height: 40px" v-if="cptch.cptch_image">
<el-form-item style="height: 40px" v-if="captcha.captcha_image">
<el-row style="height: 40px">
<el-col :span="16">
<el-input placeholder="请输入验证码" v-model="form.authcode" maxlength="6"
@ -50,7 +50,7 @@
<el-col :span="8">
<el-image
style="margin:0 4px;border-radius:4px;cursor:pointer;height: 40px"
:src="cptch.cptch_image"
:src="captcha.captcha_image"
fit="contain" @click="get_auth_code">
</el-image>
</el-col>
@ -114,7 +114,7 @@
password: '',
authcode: ''
},
cptch: {"cptch_image": '', "cptch_key": '', "length": 8},
captcha: {"captcha_image": '', "captcha_key": '', "length": 8},
activeName: 'username',
allow_ways: {'third': {}},
rutitle: '',
@ -194,23 +194,23 @@
this.loop_flag = false;
}
},
is_cptch() {
let cptch_flag = this.form.authcode.length === this.cptch.length;
if (this.cptch.cptch_key === '' || !this.cptch.cptch_key) {
cptch_flag = true
is_captcha() {
let captcha_flag = this.form.authcode.length === this.captcha.length;
if (this.captcha.captcha_key === '' || !this.captcha.captcha_key) {
captcha_flag = true
}
return cptch_flag
return captcha_flag
},
onSubmit() {
let email = this.form.email;
let password = this.form.password;
let authcode = this.form.authcode;
let login_type = 'up';
let cptch_flag = this.form.authcode.length === this.cptch.length;
if (this.cptch.cptch_key === '' || !this.cptch.cptch_key) {
cptch_flag = true
let captcha_flag = this.form.authcode.length === this.captcha.length;
if (this.captcha.captcha_key === '' || !this.captcha.captcha_key) {
captcha_flag = true
}
if (cptch_flag) {
if (captcha_flag) {
if (this.activeName === "username") {
if (email.length < 6) {
@ -248,12 +248,12 @@
"username": email,
"password": password,
"authcode": authcode,
"cptch_key": this.cptch.cptch_key,
"captcha_key": this.captcha.captcha_key,
"login_type": login_type,
};
this.login_disable = true;
if (this.cptch.geetest) {
geetest(this, params, (n_params) => {
if (this.captcha.geetest) {
geetest(this, this.form.email, params, (n_params) => {
this.do_login(n_params);
})
} else {
@ -317,7 +317,7 @@
get_auth_code() {
loginFun(data => {
if (data.code === 1000) {
this.cptch = data.data;
this.captcha = data.data;
this.allow_ways = data.data.login_type;
this.register_enable = data.data.register_enable;
this.form.authcode = '';

@ -26,7 +26,7 @@
clearable/>
</el-form-item>
<el-form-item style="height: 40px" v-if="cptch.cptch_image">
<el-form-item style="height: 40px" v-if="captcha.captcha_image">
<el-row style="height: 40px">
<el-col :span="16">
<el-input placeholder="请输入图片验证码" v-model="form.authcode" maxlength="6" clearable/>
@ -34,7 +34,7 @@
<el-col :span="8">
<el-image
style="margin:0 4px;border-radius:4px;cursor:pointer;height: 40px"
:src="cptch.cptch_image"
:src="captcha.captcha_image"
fit="contain" @click="get_auth_code">
</el-image>
</el-col>
@ -106,7 +106,7 @@
auth_token: '',
},
cptch: {"cptch_image": '', "cptch_key": '', "length": 8},
captcha: {"captcha_image": '', "captcha_key": '', "length": 8},
allow_r: false,
allow_ways: {},
rutitle: '',
@ -134,7 +134,7 @@
this.allow_ways = jdata.register_type;
this.form.authcode = '';
this.set_rtitle();
this.cptch = data.data;
this.captcha = data.data;
} else {
this.allow_r = false;
this.$message({
@ -182,19 +182,19 @@
act = 'email'
}
let authcode = this.form.authcode;
let cptch_flag = authcode.length === this.cptch.length;
if (this.cptch.cptch_key === '' || !this.cptch.cptch_key) {
cptch_flag = true
let captcha_flag = authcode.length === this.captcha.length;
if (this.captcha.captcha_key === '' || !this.captcha.captcha_key) {
captcha_flag = true
}
if (cptch_flag) {
if (captcha_flag) {
let picode = {
"authcode": authcode,
"cptch_key": this.cptch.cptch_key,
"captcha_key": this.captcha.captcha_key,
"icode": this.form.icode,
};
let params = {'act': act, 'target': this.form.email, 'ext': picode};
if (this.cptch.geetest) {
geetest(this, params, (n_params) => {
if (this.captcha.geetest) {
geetest(this, this.form.email, params, (n_params) => {
this.do_get_auth_token(n_params);
})
} else {
@ -278,11 +278,11 @@
return
}
let authcode = this.form.authcode;
let cptch_flag = authcode.length === this.cptch.length;
if (this.cptch.cptch_key === '' || !this.cptch.cptch_key) {
cptch_flag = true
let captcha_flag = authcode.length === this.captcha.length;
if (this.captcha.captcha_key === '' || !this.captcha.captcha_key) {
captcha_flag = true
}
if (cptch_flag) {
if (captcha_flag) {
if (password === password2 && password.length >= 6) {
let params = {
"username": email,
@ -292,8 +292,8 @@
"auth_key": this.form.seicode
};
this.register_disable = true;
if (this.cptch.geetest) {
geetest(this, params, (n_params) => {
if (this.captcha.geetest) {
geetest(this, this.form.email, params, (n_params) => {
this.do_register(n_params);
})
} else {

@ -17,7 +17,7 @@
<el-input v-model="form.email" prefix-icon="el-icon-user" placeholder="邮箱或手机号" autofocus
clearable/>
</el-form-item>
<el-form-item style="height: 40px" v-if="cptch.cptch_image">
<el-form-item style="height: 40px" v-if="captcha.captcha_image">
<el-row style="height: 40px">
<el-col :span="16">
<el-input placeholder="请输入验证码" v-model="form.authcode" maxlength="6"
@ -26,7 +26,7 @@
<el-col :span="8">
<el-image
style="margin:0 4px;border-radius:4px;cursor:pointer;height: 40px"
:src="cptch.cptch_image"
:src="captcha.captcha_image"
fit="contain" @click="get_auth_code">
</el-image>
</el-col>
@ -85,7 +85,7 @@
seicode: '',
auth_token: ''
},
cptch: {"cptch_image": '', "cptch_key": '', "length": 8},
captcha: {"captcha_image": '', "captcha_key": '', "length": 8},
activeName: 'username',
allow_ways: {},
rutitle: '',
@ -107,28 +107,28 @@
this.$message.error("输入有误,请检查")
}
},
is_cptch() {
let cptch_flag = this.form.authcode.length === this.cptch.length;
if (this.cptch.cptch_key === '' || !this.cptch.cptch_key) {
cptch_flag = true
is_captcha() {
let captcha_flag = this.form.authcode.length === this.captcha.length;
if (this.captcha.captcha_key === '' || !this.captcha.captcha_key) {
captcha_flag = true
}
return cptch_flag
return captcha_flag
},
onSubmit() {
let email = this.form.email;
let authcode = this.form.authcode;
let cptch_flag = this.form.authcode.length === this.cptch.length;
if (this.cptch.cptch_key === '' || !this.cptch.cptch_key) {
cptch_flag = true
let captcha_flag = this.form.authcode.length === this.captcha.length;
if (this.captcha.captcha_key === '' || !this.captcha.captcha_key) {
captcha_flag = true
}
if (cptch_flag) {
if (captcha_flag) {
let checke = checkEmail(this.form.email);
let checkp = checkphone(this.form.email);
if (checke || checkp) {
let params = {
"username": email,
"authcode": authcode,
"cptch_key": this.cptch.cptch_key,
"captcha_key": this.captcha.captcha_key,
"login_type": 'reset',
};
let seicode = this.form.seicode;
@ -140,8 +140,8 @@
params['auth_token'] = auth_token
}
this.login_disable = true;
if (this.cptch.geetest) {
geetest(this, params, (n_params) => {
if (this.captcha.geetest) {
geetest(this, this.form.email, params, (n_params) => {
this.do_login(n_params);
})
} else {
@ -196,7 +196,7 @@
get_auth_code() {
loginFun(data => {
if (data.code === 1000) {
this.cptch = data.data;
this.captcha = data.data;
this.register_enable = data.data.register_enable;
this.form.authcode = '';
} else {

@ -2,6 +2,70 @@
<div class="container">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0">
<div style="margin-top: -60px" v-if="report_flag" class="one-key-report-dialog dialog">
<a style="color: #3888fa" @click="report_flag=false">&lt;&nbsp;返回下载页</a>
<header style="text-align: center;height: 20px;margin-top: 10px">举报详情</header>
<div>
<div class="content-row">
<span>举报原因</span>
<select v-model="report_info.report_type" style="width: 100%" class="report_select">
<option v-for="item in report_info_list" :key="item.id" :label="item.name"
:value="item.id">
</option>
</select>
</div>
<div class="content-row">
<span>详细原因</span>
<textarea v-model="report_info.report_reason" placeholder="请详细说明举报原因"/>
</div>
</div>
<br/>
<div>
<div class="content-row">
<header style="text-align: center;height: 40px">举报人信息填写</header>
<div>
<span>真实姓名</span>
<label>
<input v-model="report_info.username" placeholder="请输入您的姓名"/>
</label>
</div>
</div>
<div class="content-row">
<span>联系信息</span>
<div>
<label>
<input v-model="report_info.email" :placeholder="`请输入您的${report_info_title}`"/>
</label>
</div>
</div>
<div class="content-row">
<div v-if="captcha.captcha_image" class="report_captcha">
<input placeholder="请输入图片验证码" v-model="report_info.authcode" maxlength="6" type="text"/>
<img :src="captcha.captcha_image" fit="contain" @click="get_auth_code"/>
</div>
<div class="report_phone">
<input v-model="report_info.seicode"
placeholder="验证码"/>
<button class="btn" @click="getphonecode">
获取验证码
</button>
</div>
</div>
</div>
<div class="content-row">
<div id="captcha" ref="captcha"></div>
</div>
<div class="content-row" style="text-align: center">
<button class="btn-report" @click="report_submit">立即举报</button>
</div>
</div>
<div ref="signhelp" class="signhelp screenshots-section">
<div class="signhelp-title">
iOS安装教程
@ -40,7 +104,7 @@
<!-- <span class="pattern right"><img src="@/assets/download_pattern_right.png"></span>-->
</div>
<div class="out-container " v-if="wxeasytypeflag">
<div class="out-container " v-if="wxeasytypeflag && !report_flag">
<div v-show='mcurrentappinfo.release_id' class="main">
<header>
@ -234,7 +298,8 @@
<div class="footer" style="margin-top: 30%;margin-bottom: 8px">
免责声明<br>
本网站仅提供下载托管应用为用户自行上传请甄别应用风险后进行下载
本网站仅提供下载托管应用为用户自行上传请甄别应用风险后进行下载<a class="one-key-report"
@click="get_auth_code(),report_flag=true">举报</a>
</div>
<div v-if="agent!==''">
<div v-if="ad_info.ad_uri" style="margin-bottom: 80px"/>
@ -253,7 +318,7 @@
</div>
<div v-else>
<i>
<i v-if="!report_flag">
{{this.currentappinfo.name | formatName}}
</i>
</div>
@ -273,12 +338,29 @@
<script>
import QRCode from 'qrcodejs2'
import {getdownloadurl, getShortAppinfo, gettask} from '@/restful/download'
import {getdownloadurl, getShortAppinfo, gettask, getAuthTokenFun, appReport} from '@/restful/download'
import {checkEmail, checkphone, geetest} from "@/restful/download";
export default {
name: "ShortDownload",
data() {
return {
captcha: {"captcha_image": '', "captcha_key": '', "length": 8},
report_info: {
'username': '',
'report_type': '',
'report_reason': '',
'seicode': '',
'authcode': '',
'email': '',
'auth_token': '',
'act': 'email',
},
report_info_title: '邮箱',
report_info_list: [
{'id': 0, name: '其他'},
],
report_flag: false,
signhelplist: [
{msg: '第一步 允许打开配置描述文件', url: require('@/assets/sign/step1.jpg')},
{msg: '第二步 点击右上角安装按钮', url: require('@/assets/sign/step2.jpg')},
@ -327,6 +409,98 @@
clearTimeout(this.timer);
},
methods: {
report_submit() {
let data = this.report_info;
data['app_id'] = this.currentappinfo.app_id;
if (this.report_info.auth_token && this.report_info.email && this.report_info.seicode) {
appReport(res => {
if (res.code === 1000) {
alert("信息提交成功,感谢您的支持,即将返回下载页");
// eslint-disable-next-line no-unused-vars
this.timer = setTimeout(data => {
this.report_flag = false;
}, 3000);
} else {
alert("信息提交失败,请稍后再试 " + res.msg)
}
}, {
'methods': 'POST',
'data': this.report_info
})
} else {
alert('请输入完整的信息');
}
},
getphonecode() {
if (!this.report_info.username || !this.report_info.report_reason || this.report_info.report_type === '') {
alert('请输入完整的信息');
return 0
}
if (this.report_info.act === 'email') {
if (!checkEmail(this.report_info.email)) {
alert('请输入正确的邮箱地址');
return 0
}
}
if (this.report_info.act === 'sms') {
if (!checkphone(this.report_info.email)) {
alert('请输入正确的手机号');
return 0
}
}
let picode = {
"authcode": this.report_info.authcode,
"captcha_key": this.captcha.captcha_key,
"report": this.currentappinfo.app_id
};
let params = {'act': this.report_info.act, 'target': this.report_info.email, 'ext': picode};
if (this.captcha.geetest) {
geetest(this, this.report_info.email, params, (n_params) => {
this.do_get_auth_token(n_params);
})
} else {
this.do_get_auth_token(params);
}
},
do_get_auth_token(params) {
getAuthTokenFun(data => {
if (data.code === 1000) {
alert('验证码已经发送您');
this.report_info.auth_token = data.data.auth_token;
} else {
alert(data.msg);
}
}, {"methods": 'POST', 'data': params})
},
get_auth_code() {
appReport(data => {
if (data.code === 1000) {
let jdata = data.data;
if (jdata.enable) {
this.captcha = data.data;
if (data.data.s_list) {
this.report_info_list = data.data.s_list;
}
if (jdata.report_type && jdata.report_type.sms) {
this.report_info_title = '手机号';
this.report_info.act = 'sms'
} else if (jdata.report_type && jdata.report_type.email) {
this.report_info_title = '邮箱';
this.report_info.act = 'email'
}
this.report_info.seicode = '';
this.report_info.auth_token = '';
return
}
}
alert('暂未开通举报功能');
this.report_flag = false;
}, {
"methods": "GET",
"data": {}
});
},
show_err_msg(msg) {
this.msg = msg;
alert(this.msg)
@ -702,6 +876,178 @@
</script>
<style scoped>
.dialog {
position: fixed;
width: 390px;
background-color: #fff;
left: 50%;
top: 50%;
z-index: 99999;
padding: 20px;
box-shadow: 0 0 5px rgba(0, 0, 0, .5);
transform: translate(-50%, -50%)
}
.one-key-report-dialog .content-row {
display: table;
padding: 5px;
position: relative;
width: 100%
}
.one-key-report-dialog .report_select {
position: relative;
width: 100%;
height: 50px;
border: 1px solid #D6D6D6;
font-size: 14px;
line-height: 50px;
text-indent: 15px;
cursor: pointer
}
.one-key-report-dialog .report_select:hover {
background: #F5F5F5
}
.one-key-report-dialog .report_select .dropdown-menu > option {
line-height: 40px;
cursor: pointer
}
.one-key-report-dialog .report_select .dropdown-menu > option:hover {
color: #fff;
background: #42B191
}
.one-key-report-dialog .content-row {
display: table;
padding: 5px;
position: relative;
width: 100%
}
.one-key-report-dialog .content-row input, .one-key-report-dialog .content-row label {
display: block
}
.one-key-report-dialog .content-row label {
color: #666;
font-size: 18px;
line-height: 34px;
margin-right: 30px
}
.one-key-report-dialog .content-row input {
height: 50px;
width: 100%;
margin-bottom: 10px;
padding: 5px 10px;
outline: 0;
background: #F5F5F5;
font-size: 14px;
border: 1px solid #D6D6D6
}
.one-key-report-dialog .content-row input::-moz-placeholder {
font-size: 14px;
color: #8B8E93
}
.one-key-report-dialog .content-row input:-ms-input-placeholder {
font-size: 14px;
color: #8B8E93
}
.one-key-report-dialog .content-row input::placeholder {
font-size: 14px;
color: #8B8E93
}
.one-key-report-dialog .content-row .report_captcha {
display: -ms-flexbox;
display: flex
}
.one-key-report-dialog .content-row .report_captcha input {
display: inline-block;
width: 190px;
margin-right: 20px
}
.one-key-report-dialog .content-row .report_captcha img {
width: 125px;
height: 50px;
background: #F5F5F5;
cursor: pointer
}
.one-key-report-dialog .content-row .report_phone input {
display: inline-block;
width: 190px;
margin-right: 20px
}
.one-key-report-dialog .content-row .report_phone .btn {
width: 125px;
color: #fff;
height: 50px;
background-color: #3888fa;
padding: 5px 10px;
margin-top: -5px;
font-size: 14px
}
.one-key-report-dialog .content-row textarea {
width: 100%;
height: 80px;
resize: none;
padding: 10px;
outline: 0;
color: #A9B1B3;
font-size: 14px;
background: #F5F5F5;
border: 1px solid #D6D6D6;
}
.one-key-report-dialog .content-row textarea::-moz-placeholder {
font-size: 14px;
color: #8B8E93
}
.one-key-report-dialog .content-row textarea:-ms-input-placeholder {
font-size: 14px;
color: #8B8E93
}
.one-key-report-dialog .content-row textarea::placeholder {
font-size: 14px;
color: #8B8E93
}
.one-key-report-dialog .content-row .btn-report {
color: #fff;
background-color: #3888fa;
padding: 5px 10px;
margin-top: 5px;
width: 190px;
height: 50px;
display: inline-block;
line-height: 40px;
font-size: 18px
}
.one-key-report {
color: #fff;
background-color: #32B2A7;
padding: 1px 5px;
border-radius: 15px;
}
.el-tag {
background-color: #ecf5ff;
border-color: #d9ecff;
@ -1234,6 +1580,22 @@
.main > header .scan-tips {
display: none
}
.dialog {
height: 100%;
margin: 0;
left: 0;
top: 60px;
bottom: 0;
border-radius: 0;
padding-top: 30px;
overflow-y: auto;
transform: translate(0, 0)
}
.dialog.animate {
transition: left .5s
}
}

@ -100,7 +100,7 @@
</el-form-item>
<el-form-item label="手机号码" v-if="cptch.change_type.sms">
<el-form-item label="手机号码" v-if="captcha.change_type.sms">
<el-row :gutter="36">
<el-col :span="18">
<el-input v-model="form.mobile" ref="phone" clearable
@ -108,7 +108,7 @@
</el-col>
</el-row>
</el-form-item>
<el-form-item label="图片验证码" v-if="cptch.cptch_image">
<el-form-item label="图片验证码" v-if="captcha.captcha_image">
<el-row :gutter="11">
<el-col :span="12">
<el-input placeholder="请输入图片验证码" v-model="form.authcode" maxlength="6" clearable/>
@ -116,14 +116,14 @@
<el-col :span="6">
<el-image
style="border-radius:4px;cursor:pointer;height: 40px"
:src="cptch.cptch_image"
:src="captcha.captcha_image"
fit="contain" @click="get_auth_code">
</el-image>
</el-col>
</el-row>
</el-form-item>
<el-form-item label="手机验证码" v-if="cptch.change_type.sms">
<el-form-item label="手机验证码" v-if="captcha.change_type.sms">
<el-row :gutter="11">
<el-col :span="12">
<el-input v-model="form.auth_key" prefix-icon="el-icon-mobile" placeholder="请输入您收到的验证码"
@ -220,16 +220,16 @@
<script>
import {changeInfoFun, getAuthcTokenFun, user_certification} from "@/restful";
import {AvatarUploadUtils, checkphone, geetest, getUserInfoFun} from "@/utils";
import {AvatarUploadUtils, getUserInfoFun, checkphone, geetest} from "@/utils";
export default {
name: "FirUserProfileCertification",
data() {
return {
form: {},
cptch: {
cptch_image: '',
cptch_key: '',
captcha: {
captcha_image: '',
captcha_key: '',
authcode: '',
length: 8,
change_type: {email: false, sms: false}
@ -262,7 +262,7 @@
this.$message.error("身份证输入不合法");
return false;
}
if (this.cptch.change_type.sms) {
if (this.captcha.change_type.sms) {
let checkp = checkphone(this.form.mobile);
if (!checkp) {
this.$message.error("手机号输入不合法");
@ -305,18 +305,18 @@
getsmsemailcode(act, target) {
let picode = {
"authcode": this.form.authcode,
"cptch_key": this.cptch.cptch_key,
"captcha_key": this.captcha.captcha_key,
};
if (this.cptch.cptch_image) {
if (this.captcha.captcha_image) {
if (!this.form.authcode) {
this.$message.error("图片验证码输入有误");
return;
}
let cptch_flag = this.form.authcode.length === this.cptch.length;
if (this.cptch.cptch_key === '' || !this.cptch.cptch_key) {
cptch_flag = true
let captcha_flag = this.form.authcode.length === this.captcha.length;
if (this.captcha.captcha_key === '' || !this.captcha.captcha_key) {
captcha_flag = true
}
if (!cptch_flag) {
if (!captcha_flag) {
this.$message.error("图片验证码输入有误");
return
}
@ -329,9 +329,8 @@
}
let params = {'act': act, 'target': target, 'ext': picode, 'user_id': target, 'ftype': 'certification'};
if (this.cptch.geetest) {
this.form.email = this.form.mobile;
geetest(this, params, (n_params) => {
if (this.captcha.geetest) {
geetest(this, this.form.mobile, params, (n_params) => {
this.get_phone_code(n_params);
})
} else {
@ -363,9 +362,9 @@
}
changeInfoFun(data => {
if (data.code === 1000) {
this.cptch = data.data;
if (this.cptch.cptch_key) {
this.form.cptch_key = this.cptch.cptch_key;
this.captcha = data.data;
if (this.captcha.captcha_key) {
this.form.captcha_key = this.captcha.captcha_key;
}
} else {
this.$message({

@ -109,13 +109,13 @@
<el-col :span="16">
<el-input v-model="userinfo.mobile" ref="phone" :readonly="editphone !== true"
prefix-icon="el-icon-mobile" placeholder="手机" maxlength="11" clearable
:disabled="!cptch.change_type.sms"/>
:disabled="!captcha.change_type.sms"/>
</el-col>
<el-col :span="1">
<el-button icon="el-icon-edit" @click="changePhoneValue">
</el-button>
</el-col>
<el-col :span="5" v-if="editphone === true && cptch.change_type.sms">
<el-col :span="5" v-if="editphone === true && captcha.change_type.sms">
<el-button type="success" @click="savePhone" plain
class="save-button">
保存
@ -125,7 +125,7 @@
</el-form-item>
<el-form-item label="图片验证码" style="height: 40px"
v-if="editphone === true && cptch.cptch_image && cptch.change_type.sms">
v-if="editphone === true && captcha.captcha_image && captcha.change_type.sms">
<el-row style="height: 40px" :gutter="36">
<el-col :span="14">
<el-input placeholder="请输入图片验证码" v-model="userinfo.authcode" maxlength="6" clearable/>
@ -133,14 +133,14 @@
<el-col :span="8">
<el-image
style="margin:0 4px;border-radius:4px;cursor:pointer;height: 40px"
:src="cptch.cptch_image"
:src="captcha.captcha_image"
fit="contain" @click="get_auth_code">
</el-image>
</el-col>
</el-row>
</el-form-item>
<el-form-item label="手机验证码" v-if="editphone === true && cptch.change_type.sms">
<el-form-item label="手机验证码" v-if="editphone === true && captcha.change_type.sms">
<el-row :gutter="36">
<el-col :span="16">
<el-input v-model="userinfo.auth_key" prefix-icon="el-icon-mobile" placeholder="验证码"
@ -162,13 +162,13 @@
<el-col :span="16">
<el-input v-model="userinfo.email" ref="email" :readonly="editemail !== true"
prefix-icon="el-icon-bank-card" placeholder="邮箱" maxlength="20" clearable
:disabled="!cptch.change_type.email"/>
:disabled="!captcha.change_type.email"/>
</el-col>
<el-col :span="1">
<el-button icon="el-icon-edit" @click="changeemailValue">
</el-button>
</el-col>
<el-col :span="5" v-if="editemail === true && cptch.change_type.email">
<el-col :span="5" v-if="editemail === true && captcha.change_type.email">
<el-button type="success" @click="saveemail" plain
class="save-button">
保存
@ -179,7 +179,7 @@
<el-form-item label="图片验证码" style="height: 40px"
v-if="editemail === true && cptch.cptch_image && cptch.change_type.email">
v-if="editemail === true && captcha.captcha_image && captcha.change_type.email">
<el-row style="height: 40px" :gutter="36">
<el-col :span="14">
<el-input placeholder="请输入图片验证码" v-model="userinfo.authcode" maxlength="6" clearable/>
@ -187,14 +187,14 @@
<el-col :span="8">
<el-image
style="margin:0 4px;border-radius:4px;cursor:pointer;height: 40px"
:src="cptch.cptch_image"
:src="captcha.captcha_image"
fit="contain" @click="get_auth_code">
</el-image>
</el-col>
</el-row>
</el-form-item>
<el-form-item label="邮箱验证码" v-if="editemail === true && cptch.change_type.email">
<el-form-item label="邮箱验证码" v-if="editemail === true && captcha.change_type.email">
<el-row :gutter="36">
<el-col :span="16">
<el-input v-model="userinfo.auth_key" prefix-icon="el-icon-mobile" placeholder="验证码"
@ -295,7 +295,7 @@
editdomain_name: false,
edituser_name: false,
editposition: false,
cptch: {"cptch_image": '', "cptch_key": '', "length": 8, change_type: {email: false, sms: false}},
captcha: {"captcha_image": '', "captcha_key": '', "length": 8, change_type: {email: false, sms: false}},
form: {},
wx_login_qr_url: '',
wx_visible: false,
@ -408,8 +408,8 @@
get_auth_code() {
changeInfoFun(data => {
if (data.code === 1000) {
this.cptch = data.data;
this.userinfo.cptch_key = this.cptch.cptch_key;
this.captcha = data.data;
this.userinfo.captcha_key = this.captcha.captcha_key;
if (this.userinfo.authcode) {
this.userinfo.authcode = '';
}
@ -445,7 +445,7 @@
return {
auth_token: this.userinfo.auth_token,
auth_key: this.userinfo.auth_key,
cptch_key: this.userinfo.cptch_key,
captcha_key: this.userinfo.captcha_key,
authcode: this.userinfo.authcode,
};
},
@ -554,14 +554,13 @@
getsmsemailcode(act, target) {
let picode = {
"authcode": this.userinfo.authcode,
"cptch_key": this.cptch.cptch_key,
"captcha_key": this.captcha.captcha_key,
};
let params = {
'act': act, 'target': target, 'ext': picode
};
if (this.cptch.geetest) {
this.form.email = target;
geetest(this, params, (n_params) => {
if (this.captcha.geetest) {
geetest(this, this.form.email, target, params, (n_params) => {
this.do_get_auth_token(n_params);
})
} else {

@ -3,7 +3,23 @@ import Download from "@/Download";
import router from "@/router/download";
import 'element-ui/lib/theme-chalk/index.css'
import {Button, Container, Divider, Input, Link, Main, Message} from "element-ui";
import {
Button,
Container,
Divider,
Input,
Link,
Main,
Message,
Select,
Option,
Header,
Form,
FormItem,
Row,
Col,
Notification
} from "element-ui";
import VueLazyload from 'vue-lazyload'
Vue.use(Link);
@ -12,7 +28,15 @@ Vue.use(Button);
Vue.use(Container);
Vue.use(Main);
Vue.use(Divider);
Vue.use(Select);
Vue.use(Option);
Vue.use(Header);
Vue.use(Form);
Vue.use(FormItem);
Vue.use(Row);
Vue.use(Col);
Vue.prototype.$message = Message;
Vue.prototype.$notify = Notification;
Vue.config.productionTip = false;

@ -6,8 +6,33 @@ const DOMAIN = process.env.base_env.baseShortUrl;
const APIPATH = '/api/v1/fir/server';
let USERSEVER = DOMAIN + APIPATH;
function ErrorMsg(error) {
if (error && error.response) {
switch (error.response.status) {
case 400:
error.message = '请求错误(400)';
break;
case 403:
error.message = '拒绝访问(403)';
break;
case 404:
error.message = '请求出错(404)';
break;
case 429:
error.message = '您的 IP 访问频繁,请稍后再次尝试';
break;
default:
error.message = `连接出错(${error.response.status})!`;
}
} else {
error.message = '连接服务器失败!';
}
if (error.message === 'Network Error') {
alert('网络连接失败')
}
}
function getData(url, params = {}, callBack) {
function getData(methods = 'GET', url, params = {}, callBack) {
var uri = '';
@ -25,6 +50,28 @@ function getData(url, params = {}, callBack) {
uri = "?" + uri
}
url = url + uri;
if (methods === "PUT") {
Axios
.put(url, params)
.then(function (response) {
callBack(response.data);
})
.catch(function (error) {
ErrorMsg(error);
callBack({"code": -1});
});
} else if (methods === 'POST') {
Axios
.post(url, params)
.then(function (response) {
callBack(response.data);
})
.catch(function (error) {
ErrorMsg(error);
callBack({"code": -1});
});
} else
Axios
.get(url, params)
.then(function (response) {
@ -35,30 +82,7 @@ function getData(url, params = {}, callBack) {
}
})
.catch(function (error) {
if (error && error.response) {
switch (error.response.status) {
case 400:
error.message = '请求错误(400)';
break;
case 403:
error.message = '拒绝访问(403)';
break;
case 404:
error.message = '请求出错(404)';
break;
case 429:
error.message = '您的 IP 访问频繁,请稍后再次尝试';
break;
default:
error.message = `连接出错(${error.response.status})!`;
}
} else {
error.message = '连接服务器失败!';
}
if (error.message === 'Network Error') {
alert('网络连接失败')
}
ErrorMsg(error);
callBack({"code": -1});
});
}
@ -67,6 +91,7 @@ function getData(url, params = {}, callBack) {
/**根据短链接获取应用信息 */
export function getShortAppinfo(callBack, params) {
getData(
'GET',
USERSEVER + '/short/' + params.short,
params,
data => {
@ -79,6 +104,7 @@ export function getShortAppinfo(callBack, params) {
/**获取下载的url */
export function getdownloadurl(callBack, params) {
getData(
'GET',
USERSEVER + '/install/' + params.app_id,
params.data,
data => {
@ -90,6 +116,7 @@ export function getdownloadurl(callBack, params) {
/**获取签名任务状态 */
export function gettask(callBack, params) {
getData(
'GET',
USERSEVER + '/task/' + params.short,
params.data,
data => {
@ -97,3 +124,81 @@ export function gettask(callBack, params) {
},
);
}
/**应用举报 */
export function appReport(callBack, params) {
getData(
params.methods,
USERSEVER + '/report',
params.data,
data => {
callBack(data);
},
);
}
/**token */
export function loginFun(callBack, params) {
getData(
params.methods,
USERSEVER + '/login',
params.data,
data => {
callBack(data);
},
);
}
/**获取验证token */
export function getAuthTokenFun(callBack, params) {
getData(
params.methods,
USERSEVER + '/auth',
params.data,
data => {
callBack(data);
},
);
}
export function checkEmail(email) {
let re = /^(\w-*\.*)+@(\w-?)+(\.\w{2,})+$/;
return re.test(email);
}
export function checkphone(email) {
let re = /^1\d{10}$/;
return re.test(email);
}
export function geetest(self, uid, params, callback) {
loginFun(res => {
if (res.code === 1000) {
let data = res.data;
// eslint-disable-next-line no-undef
initGeetest({
gt: data.gt,
challenge: data.challenge,
new_captcha: data.new_captcha, // 用于宕机时表示是新验证码的宕机
offline: !data.success, // 表示用户后台检测极验服务器是否宕机,一般不需要关注
product: "float", // 产品形式,包括:float,popup
width: "100%"
}, (captchaObj) => {
self.$refs.captcha.innerHTML = '';
captchaObj.appendTo("#captcha");
captchaObj.onReady(() => {
}).onSuccess(() => {
params.geetest = captchaObj.getValidate();
callback(params);
}).onError(() => {
captchaObj.destroy();
});
});
} else {
alert(res.msg);
}
}, {
"methods": "PUT",
"data": {user_id: uid}
});
}

@ -707,3 +707,18 @@ export function DeviceBillInfo(callBack, params, load = true) {
true
);
}
/**应用举报 */
export function appReport(callBack, params, load = true) {
getData(
params.methods,
USERSEVER + '/report',
params.data,
data => {
callBack(data);
},
load,
true,
true
);
}

@ -346,7 +346,7 @@ export function ImgToBase64(url, callback) {
};
}
export function geetest(self, params, callback) {
export function geetest(self, uid, params, callback) {
const loading = self.$loading({
lock: true,
text: 'Loading',
@ -385,7 +385,7 @@ export function geetest(self, params, callback) {
}
}, {
"methods": "PUT",
"data": {user_id: self.form.email}
"data": {user_id: uid} //self.form.email
});
}

@ -48,7 +48,7 @@ const mshort = {
// 模板来源
template: 'public/short.html',
// 在 dist/short.html 的输出
filename: 'mshort.html',
filename: 'short.html',
// 当使用 title 选项时,
// template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
title: '应用下载',
@ -70,7 +70,7 @@ const short = {
// 提取出来的通用 chunk 和 vendor chunk。
chunks: ['chunk-vendors', 'chunk-common', 'short', 'chunk-commons', 'runtime']
};
let pages = {index, short};
let pages = {index, short, mshort};
const page = argv[3];
if (page) {
for (const key of Object.keys(pages)) {

@ -29,7 +29,7 @@ class LoginView(APIView):
receive = request.data
username = receive.get("username", None)
if LOGIN.get("captcha"):
is_valid = valid_captcha(receive.get("cptch_key", None), receive.get("authcode", None), username)
is_valid = valid_captcha(receive.get("captcha_key", None), receive.get("authcode", None), username)
else:
is_valid = True
if is_valid:

@ -573,6 +573,27 @@ class RemoteClientInfo(models.Model):
return "%s-%s" % (self.remote_addr, self.description)
class AppReportInfo(models.Model):
app_id = models.ForeignKey(to="Apps", on_delete=models.SET_NULL, verbose_name="应用信息",
null=True, blank=True)
app_name = models.CharField(max_length=32, blank=True, null=True, verbose_name="应用名称")
bundle_id = models.CharField(max_length=64, blank=True, verbose_name="bundle id")
remote_addr = models.GenericIPAddressField(verbose_name="远程IP地址")
report_type_choices = ((0, '侵权'), (1, '色情'), (2, '赌博'), (3, '欺诈'), (4, '暴力'), (5, '其他'),)
report_type = models.SmallIntegerField(choices=report_type_choices, default=5, verbose_name="举报类型")
report_reason = models.CharField(max_length=512, verbose_name="举报详情")
email = models.CharField(max_length=64, verbose_name="联系方式")
username = models.CharField(max_length=64, verbose_name="姓名")
created_time = models.DateTimeField(auto_now_add=True, verbose_name="访问时间")
class Meta:
verbose_name = '应用举报信息'
verbose_name_plural = "应用举报信息"
def __str__(self):
return "%s-%s" % (self.app_name, self.report_reason)
class DeviceQueue(models.Model):
app_id = models.ForeignKey(to='Apps', on_delete=models.CASCADE, verbose_name="应用id")
udid = models.CharField(max_length=64, verbose_name="udid唯一标识", db_index=True)

@ -24,6 +24,7 @@ from api.views.login import LoginView, UserInfoView, RegistView, AuthorizationVi
from api.views.logout import LogoutView
from api.views.order import PriceView, OrderView, PaySuccess
from api.views.receiveudids import IosUDIDView, TaskView
from api.views.report import ReportView
from api.views.storage import StorageView
from api.views.supersign import DeveloperView, SuperSignUsedView, AppUDIDUsedView, SuperSignCertView, DeviceUsedBillView
from api.views.thirdlogin import ValidWxChatToken, ThirdWxAccount
@ -52,6 +53,7 @@ urlpatterns = [
re_path(r"^task/(?P<short>\w+)$", TaskView.as_view()),
re_path("^analyse$", AppAnalyseView.as_view()),
re_path("^advert$", UserAdInfoView.as_view()),
re_path("^report$", ReportView.as_view()),
re_path("^supersign/developer$", DeveloperView.as_view()),
re_path("^supersign/devices$", SuperSignUsedView.as_view()),
re_path("^supersign/udid$", AppUDIDUsedView.as_view()),

@ -38,11 +38,13 @@ def make_token(release_id, time_limit=60, key='', force_new=False):
return token
def verify_token(token, release_id):
def verify_token(token, release_id, success_once=False):
try:
values = cache.get(token)
if values and release_id == values.get("data", None):
logger.debug(f"verify_token token:{token} release_id:{release_id} success")
if success_once:
cache.delete(token)
return True
except Exception as e:
logger.error(f"verify_token token:{token} release_id:{release_id} failed Exception:{e}")

@ -771,3 +771,9 @@ class BillInfoSerializer(serializers.ModelSerializer):
return f"{obj.user_id.first_name}-{self.get_action(obj)} +{obj.number} 设备数"
else:
return f"{obj.to_user_id.first_name} {self.get_action(obj)} -{obj.number} 设备数"
class AppReportSerializer(serializers.ModelSerializer):
class Meta:
model = models.AppReportInfo
exclude = ["id"]

@ -107,7 +107,7 @@ def get_sender_token(sender, user_id, target, action, msg=None):
code = msg
token = make_token(code, time_limit=300, key=user_id)
TmpCache.set_tmp_cache(user_id, token, target)
if action in ('change', 'password', 'register', 'login'):
if action in ('change', 'password', 'register', 'login', 'common'):
sender.send_msg_by_act(target, code, action)
elif action == 'msg':
sender.send_email_msg(target, msg)
@ -124,8 +124,8 @@ def get_sender_sms_token(key, phone, action, msg=None):
return False, False
def is_valid_sender_code(key, token, code):
return verify_token(token, code), TmpCache.get_tmp_cache(key, token)
def is_valid_sender_code(key, token, code, success_once=False):
return verify_token(token, code, success_once), TmpCache.get_tmp_cache(key, token)
def get_sender_email_token(key, email, action, msg=None):

@ -5,7 +5,7 @@ from django.core.cache import cache
from rest_framework.response import Response
from rest_framework.views import APIView
from api.models import Token, UserInfo, UserCertificationInfo, CertificationInfo
from api.models import Token, UserInfo, UserCertificationInfo, CertificationInfo, Apps
from api.utils.auth import ExpiringTokenAuthentication
from api.utils.baseutils import is_valid_phone, is_valid_email, get_real_ip_address
from api.utils.geetest.geetest_utils import first_register, second_validate
@ -18,7 +18,7 @@ from api.utils.throttle import VisitRegister1Throttle, VisitRegister2Throttle, G
from api.utils.utils import get_captcha, valid_captcha, \
get_sender_sms_token, is_valid_sender_code, get_sender_email_token, get_random_username, \
check_username_exists, set_user_token
from fir_ser.settings import REGISTER, LOGIN, CHANGER
from fir_ser.settings import REGISTER, LOGIN, CHANGER, REPORT
logger = logging.getLogger(__name__)
@ -203,6 +203,49 @@ def check_change_userinfo(target, act, key, user, ftype=None):
return res
def check_common_info(target, act):
res = BaseResponse()
res.data = {}
times_key = "%s_%s_%s" % ('report', act, target)
if act == "sms":
if is_valid_phone(target):
if login_auth_failed("get", times_key):
login_auth_failed("set", times_key)
token, code = get_sender_sms_token(act, target, 'common')
if token:
res.data["auth_token"] = token
else:
res.code = 1009
res.msg = "短信服务异常,请联系管理员"
else:
res.code = 1009
res.msg = "该手机号今日使用次数已经达到上限"
else:
res.code = 1005
res.msg = "手机号校验失败"
elif act == "email":
if is_valid_email(target):
if login_auth_failed("get", times_key):
login_auth_failed("set", times_key)
token, code = get_sender_email_token(act, target, 'common')
if token:
res.data["auth_token"] = token
else:
res.code = 1009
res.msg = "邮件服务异常,请联系管理员"
else:
res.code = 1009
res.msg = "该邮箱今日使用次数已经达到上限"
else:
res.code = 1006
res.msg = "邮箱校验失败"
else:
res.code = 1007
res.msg = "信息发送失败"
return res
class LoginView(APIView):
throttle_classes = [VisitRegister1Throttle, VisitRegister2Throttle]
@ -211,7 +254,7 @@ class LoginView(APIView):
receive = request.data
username = receive.get("username", None)
if LOGIN.get("captcha"):
is_valid = valid_captcha(receive.get("cptch_key", None), receive.get("authcode", None), username)
is_valid = valid_captcha(receive.get("captcha_key", None), receive.get("authcode", None), username)
else:
is_valid = True
if is_valid:
@ -466,7 +509,7 @@ class UserInfoView(APIView):
email = data.get("email", None)
if mobile or email:
if CHANGER.get('captcha'):
is_valid = valid_captcha(data.get("cptch_key", None), data.get("authcode", None), request)
is_valid = valid_captcha(data.get("captcha_key", None), data.get("authcode", None), request)
if not is_valid:
res.code = 1008
res.msg = "图片验证码异常"
@ -578,8 +621,11 @@ class AuthorizationView(APIView):
res.msg = "邀请码已失效"
return Response(res.dict)
if ext and ext.get('report'):
REGISTER = REPORT
if REGISTER.get("captcha"):
is_valid = valid_captcha(ext.get("cptch_key", None), ext.get("authcode", None), target)
is_valid = valid_captcha(ext.get("captcha_key", None), ext.get("authcode", None), target)
if ext and is_valid:
pass
else:
@ -595,6 +641,14 @@ class AuthorizationView(APIView):
res.code = 1018
res.msg = "geetest验证有误"
return Response(res.dict)
if ext and ext.get('report'):
app_obj = Apps.objects.filter(app_id=ext.get('report')).first()
if app_obj:
res = check_common_info(target, act)
else:
res.code = 1003
res.msg = '未授权,请重新提交'
return Response(res.dict)
res = check_register_userinfo(target, act, 'register')
@ -613,7 +667,7 @@ class ChangeAuthorizationView(APIView):
ext = request.data.get("ext", None)
f_type = request.data.get("ftype", None)
if REGISTER.get("captcha"):
if ext and valid_captcha(ext.get("cptch_key", None), ext.get("authcode", None), target):
if ext and valid_captcha(ext.get("captcha_key", None), ext.get("authcode", None), target):
pass
else:
res.code = 1009
@ -701,8 +755,9 @@ class CertificationView(APIView):
try:
if CHANGER.get("captcha"):
if data and valid_captcha(data.get("cptch_key", None), data.get("authcode", None), data.get("mobile")):
del data["cptch_key"]
if data and valid_captcha(data.get("captcha_key", None), data.get("authcode", None),
data.get("mobile")):
del data["captcha_key"]
del data["authcode"]
else:
res.code = 1009

@ -0,0 +1,76 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# project: 11月
# author: NinEveN
# date: 2021/11/4
import logging
from rest_framework.response import Response
from rest_framework.views import APIView
from api.models import Apps, AppReportInfo
from api.utils.baseutils import get_real_ip_address
from api.utils.modelutils import add_remote_info_from_request
from api.utils.response import BaseResponse
from api.utils.serializer import AppReportSerializer
from api.utils.storage.caches import login_auth_failed
from api.utils.throttle import InstallThrottle2
from api.utils.utils import is_valid_sender_code, get_captcha, get_choices_dict
from fir_ser.settings import REPORT
logger = logging.getLogger(__name__)
class ReportView(APIView):
throttle_classes = [InstallThrottle2]
def get(self, request):
response = BaseResponse()
response.data = {}
allow_f = REPORT.get("enable")
if allow_f:
if REPORT.get("captcha"):
response.data = get_captcha()
if REPORT.get("geetest"):
response.data['geetest'] = True
response.data['report_type'] = REPORT.get("report_type")
response.data['s_list'] = get_choices_dict(AppReportInfo.report_type_choices)
response.data['enable'] = allow_f
return Response(response.dict)
def post(self, request):
res = BaseResponse()
data = request.data
msg = f"add new app report data:{data}"
logger.info(msg)
email = data.get('email', '')
is_valid, target = is_valid_sender_code(data.get('act'), data.get("auth_token", None),
data.get("seicode", None), True)
if is_valid and str(target) == str(email):
if login_auth_failed("get", email):
add_remote_info_from_request(request, msg)
if data.get('app_id'):
app_obj = Apps.objects.filter(app_id=data.get('app_id')).first()
ext_info = {
'app_name': app_obj.name,
'bundle_id': app_obj.bundle_id,
'remote_addr': get_real_ip_address(request),
'app_id': app_obj.pk
}
data.update(ext_info)
serializer = AppReportSerializer(data=data, context={'user_obj': request.user})
if serializer.is_valid():
serializer.save()
else:
logger.info(f"add new app report failed")
res.msg = serializer.errors
res.code = 1005
else:
res.code = 1006
logger.error("email:%s failed too try , locked" % (email,))
res.msg = "失败次数过多,已被锁定,请1小时之后再次尝试"
else:
res.code = 1001
res.msg = "验证码有误或失效"
return Response(res.dict)

@ -126,6 +126,15 @@ class AUTHCONF(object):
},
}
}
REPORT = {
"enable": True,
"captcha": True, # 是否开启注册字母验证码
"geetest": False, # 是否开启geetest验证,如要开启请先配置geetest
"report_type": {
'sms': False, # 短信举报
'email': True, # 邮件举报
}
}
class STORAGEKEYCONF(object):
@ -186,13 +195,14 @@ class SENDERCONF(object):
'use_ssl': True,
'username': 'flyapps@126.com',
'password': 'GGHFEUMZBRZIFZGQ',
'form': 'FlyApp Validation <flyapps@126.com>',
'form': 'fly分发平台 <flyapps@126.com>',
'subject': '%(code)s验证',
'template_code': {
'login': '欢迎使用FLY 应用分发平台。 您的验证码%(code)s ,您正在登录,若非本人操作,请勿泄露。',
'change': '欢迎使用FLY 应用分发平台。 您的验证码%(code)s ,您正在尝试变更重要信息,请妥善保管账户信息。',
'register': '欢迎使用FLY 应用分发平台。 您的验证码%(code)s ,您正在注册成为新用户,感谢您的支持!',
'password': '欢迎使用FLY 应用分发平台。 您的新密码为%(code)s , 请用新密码登录之后,及时修改密码,并妥善保管账户信息。'
'password': '欢迎使用FLY 应用分发平台。 您的新密码为%(code)s , 请用新密码登录之后,及时修改密码,并妥善保管账户信息。',
'common': '欢迎使用FLY 应用分发平台。 您的验证码%(code)s , 若非本人操作,请忽略。'
}
},
'active': True
@ -209,7 +219,8 @@ class SENDERCONF(object):
'login': 'SMS_216700569',
'change': 'SMS_216700566',
'register': 'SMS_216700567',
'password': 'SMS_222341718'
'password': 'SMS_222341718',
'common': 'SMS_227259072'
}
},
'active': True
@ -225,7 +236,8 @@ class SENDERCONF(object):
'login': '1',
'change': '1',
'register': '1',
'password': '1'
'password': '1',
'common': '1',
}
},
'active': False

@ -192,7 +192,7 @@ REGISTER = AUTHCONF.REGISTER
# 个人资料修改修改也会使用该配置
CHANGER = AUTHCONF.CHANGER
LOGIN = AUTHCONF.LOGIN
REPORT = AUTHCONF.REPORT
THIRD_PART_CONFIG_KEY_INFO = {
# APP存储配置
'storage_key': STORAGEKEYCONF.STORAGE,

Loading…
Cancel
Save