super_signature
nineven 5 years ago
parent 4e60166ecc
commit 870646daeb
  1. 10
      fir_client/src/components/FirHeader.vue
  2. 303
      fir_client/src/components/FirSuperSignBase.vue
  3. 2
      fir_client/src/components/FirUserProfileBase.vue
  4. 53
      fir_client/src/restful/index.js
  5. 17
      fir_client/src/router/index.js
  6. 4
      fir_ser/api/models.py
  7. 5
      fir_ser/api/urls.py
  8. 36
      fir_ser/api/utils/app/supersignutils.py
  9. 49
      fir_ser/api/utils/serializer.py
  10. 2
      fir_ser/api/views/receiveudids.py
  11. 93
      fir_ser/api/views/supersign.py
  12. 2
      fir_ser/supersign/scripts/apple_api.rb

@ -25,6 +25,9 @@
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="userinfo">个人资料</el-dropdown-item>
<el-dropdown-item command="chpasswd">修改密码</el-dropdown-item>
<el-dropdown-item command="storage">存储管理</el-dropdown-item>
<el-dropdown-item command="supersign">超级签名</el-dropdown-item>
<el-dropdown-item command="exit">退出</el-dropdown-item>
</el-dropdown-menu>
@ -61,7 +64,12 @@ import {logout} from '../restful'
this.$router.push({name: 'FirUserProfileInfo'})
} else if (command === 'chpasswd') {
this.$router.push({name: 'FirUserProfileChangePwd'})
}else if(command === 'exit'){
}else if (command === 'storage') {
this.$router.push({name: 'FirUserProfileStorage'})
}else if (command === 'supersign') {
this.$router.push({name: 'FirSuperSignBase'})
}
else if(command === 'exit'){
logout(data => {
if (data.code === 1000) {
this.$message.success("退出成功");

@ -0,0 +1,303 @@
<template>
<el-main>
<el-tabs v-model="activeName" type="border-card" @tab-click="handleClick" tab-position="top">
<el-tab-pane label="开发者账户" name="iosdeveloper">
<el-table
:data="app_developer_lists"
border
stripe
style="width: 100%">
<el-table-column
fixed
prop="email"
label="用户"
width="220">
</el-table-column>
<el-table-column
prop="is_actived"
label="是否激活"
width="100">
<template slot-scope="scope" >
<el-button v-if="scope.row.is_actived === true" type="success" size="small">已激活</el-button>
<el-button v-else type="danger" size="small">未激活</el-button>
</template>
</el-table-column>
<el-table-column
prop="usable_number"
label="可用设备数"
width="100">
</el-table-column>
<el-table-column
prop="use_number"
label="已消耗设备数"
width="120">
</el-table-column>
<el-table-column
:formatter="formatter"
prop="updated_time"
label="更新时间"
width="160">
</el-table-column>
<el-table-column
prop="description"
label="备注"
>
</el-table-column>
<el-table-column
fixed="right"
label="操作"
width="150">
<template slot-scope="scope" >
<el-button
size="mini"
@click="handleEdit(scope.$index, scope.row)">编辑</el-button>
<el-button
size="mini"
type="danger"
@click="handleDelete(scope.$index, scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="添加开发者">添加开发者</el-tab-pane>
<el-tab-pane label="设备消耗" name="useddevices">
<el-table
:data="app_devices_lists"
border
stripe
style="width: 100%">
<el-table-column
fixed
prop="device_udid"
label="设备ID"
>
</el-table-column>
<el-table-column
prop="device_name"
label="设备名称"
width="120">
</el-table-column>
<el-table-column
prop="bundle_id"
label="应用ID"
width="180">
</el-table-column>
<el-table-column
prop="bundle_name"
label="应用名称"
width="160">
</el-table-column>
<el-table-column
prop="developer_id"
label="开发者ID"
width="200">
</el-table-column>
<el-table-column
:formatter="deviceformatter"
prop="created_time"
label="授权时间"
width="160">
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="设备管理" name="devicesudid">
<el-input
style="width: 30%;margin-right: 30px;margin-bottom: 10px"
v-model="udidsearch"
clearable
placeholder="输入UDID" />
<el-input
style="width: 20%;margin-right: 30px;margin-bottom: 10px"
v-model="Bundleidsearch"
clearable
placeholder="输入BundleID" />
<el-button type="primary" icon="el-icon-search" @click="iosdevicesudidFun('GET',{udid:udidsearch,bundleid:Bundleidsearch})">搜索</el-button>
<el-table
:data="app_udid_lists"
border
stripe
style="width: 100%">
<el-table-column
fixed
prop="udid"
label="设备ID"
>
<template slot-scope="scope">
<el-popover trigger="hover" placement="top">
<p>Bundle_ID: {{ scope.row.bundle_id }}</p>
<p>应用名称: {{ scope.row.bundle_name }}</p>
<p>UDID: {{ scope.row.udid }}</p>
<div slot="reference" class="name-wrapper">
<el-tag size="medium">{{ scope.row.udid }}</el-tag>
</div>
</el-popover>
</template>
</el-table-column>
<el-table-column
prop="imei"
label="imei"
width="180">
</el-table-column>
<el-table-column
prop="product"
label="设备名称"
width="100">
</el-table-column>
<el-table-column
prop="version"
label="设备型号"
width="100">
</el-table-column>
<el-table-column
prop="serial"
label="设备序列号"
width="150">
</el-table-column>
<el-table-column
:formatter="deviceformatter"
prop="created_time"
label="添加时间"
width="160">
</el-table-column>
<el-table-column
fixed="right"
label="操作"
width="80">
<template slot-scope="scope" >
<el-button
size="mini"
type="danger"
@click="iosdevicesudidFun('DELETE',{id:scope.row.id,aid:scope.row.app_id})">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
</el-tabs>
</el-main>
</template>
<script>
import {iosdeveloper, iosdevices,iosdevicesudid } from "../restful";
export default {
name: "FirSuperSignBase",
data() {
return {
app_developer_lists:[],
app_devices_lists:[],
app_udid_lists:[],
activeName:"iosdeveloper",
udidsearch:"",
Bundleidsearch:""
}
},
methods: {
handleDelete(b){
// eslint-disable-next-line no-console
console.log(b)
},
handleClick(tab, event) {
// eslint-disable-next-line no-console
console.log(tab, event);
if(tab.name === "useddevices"){
this.iosdevicesFun()
}else if(tab.name === "devicesudid"){
this.iosdevicesudidFun('GET')
}
},
// eslint-disable-next-line no-unused-vars
deviceformatter(row, column){
let stime = row.created_time;
if (stime) {
stime = stime.split(".")[0].split("T");
return stime[0] + " " + stime[1]
} else
return '';
},
// eslint-disable-next-line no-unused-vars
formatter(row, column){
let stime = row.updated_time;
if (stime) {
stime = stime.split(".")[0].split("T");
return stime[0] + " " + stime[1]
} else
return '';
},
iosdevicesFun(){
iosdevices(data=>{
if(data.code === 1000){
this.app_devices_lists = data.data;
// eslint-disable-next-line no-console
console.log(data)
}
},{
"methods":"GET"
})
},
iosdeveloperFun(){
iosdeveloper(data=>{
if(data.code === 1000){
this.app_developer_lists = data.data;
this.$store.dispatch("getUser",data.userinfo);
this.$store.dispatch('doucurrentapp', {});
// eslint-disable-next-line no-console
console.log(data)
}
},{
"methods":"GET"
})
},
iosdevicesudidFun(action,data){
iosdevicesudid(data=>{
if(data.code === 1000){
this.app_udid_lists = data.data;
}
},{
"methods":action,"data":data
})
}
}, mounted() {
this.iosdeveloperFun()
}, watch: {
// eslint-disable-next-line no-unused-vars
udidsearch: function (val, oldVal) {
// this.searchapps()
},
},filters:{
},computed:{
}
}
</script>
<style scoped>
.el-main {
margin: 10px auto 100px;
width: 1166px;
position: relative;
padding-bottom: 1px;
background-color: #bfe7f9;
color: #9b9b9b;
-webkit-font-smoothing: antialiased;
border-radius: 1%;
}
</style>

@ -66,7 +66,7 @@
import {uploadaliyunoss, uploadlocalstorage, uploadqiniuoss} from "../utils";
export default {
name: "FirUserProfile",
name: "FirUserProfileBase",
data() {
return {
imageUrl: '',

@ -10,9 +10,11 @@ Axios.defaults.httpsAgent = new https.Agent({
});
// Axios.defaults.baseURL='';
const USERSEVER = 'https://fly.dvcloud.xin/api/v1/fir/server';
const DOMAIN = 'https://fly.dvcloud.xin';
// const USERSEVER = 'http://192.168.1.112:8000/api/v1/fir/server';
// const DOMAIN = 'http://192.168.8.236:8000';
const APIPATH='/api/v1/fir/server';
let USERSEVER = DOMAIN+APIPATH;
export function set_auth_token() {
@ -357,7 +359,7 @@ export function getuploadurl() {
return USERSEVER + '/upload'
}
export function getplisturl() {
return USERSEVER + '/download'
return DOMAIN + '/download'
}
@ -435,3 +437,48 @@ export function uploadimgs(callBack, params, load = true) {
);
}
/**超级签名 苹果开发者信息 */
export function iosdeveloper(callBack, params, load = true) {
getData(
params.methods,
USERSEVER + '/supersign/developer',
params.data,
data => {
callBack(data);
},
load,
true,
true
);
}
/**超级签名 设备消耗信息 */
export function iosdevices(callBack, params, load = true) {
getData(
params.methods,
USERSEVER + '/supersign/devices',
params.data,
data => {
callBack(data);
},
load,
true,
true
);
}
/**超级签名 设备udid信息 */
export function iosdevicesudid(callBack, params, load = true) {
// eslint-disable-next-line no-console
getData(
params.methods,
USERSEVER + '/supersign/udid',
params.data,
data => {
callBack(data);
},
load,
true,
true
);
}

@ -23,11 +23,13 @@ import FirAppInfosbaseinfo from "@/components/FirAppInfosbaseinfo";
import FirAppInfossecurity from "@/components/FirAppInfossecurity";
import FirAppInfosdevices from "@/components/FirAppInfosdevices";
import FirAppInfoscombo from "@/components/FirAppInfoscombo";
import FirUserProfile from "@/components/FirUserProfileBase";
import FirUserProfileBase from "@/components/FirUserProfileBase";
import FirUserProfileInfo from "@/components/FirUserProfileInfo";
import FirUserProfileChangePwd from "@/components/FirUserProfileChangePwd";
import FirUserProfileStorage from "@/components/FirUserProfileStorage";
import FirSuperSignBase from "@/components/FirSuperSignBase";
const router = new VueRouter({
mode:'history',
routes: [
@ -91,7 +93,7 @@ const router = new VueRouter({
children: [
{
path: '',
component: FirUserProfile,
component: FirUserProfileBase,
children: [
{
path: 'info',
@ -116,6 +118,17 @@ const router = new VueRouter({
name: 'FirLogin',
component: FirLogin
},
{
path: '/supersign',
component: FirAppBase,
children: [
{
path: '',
name: 'FirSuperSignBase',
component: FirSuperSignBase,
}
]
},
{
path: '/register',
name: 'FirRegist',

@ -168,7 +168,7 @@ class AppStorage(models.Model):
class AppUDID(models.Model):
app_id = models.ForeignKey(to="Apps", on_delete=models.CASCADE, verbose_name="属于哪个APP")
udid = models.CharField(max_length=64, unique=True,verbose_name="udid唯一标识",db_index=True)
udid = models.CharField(max_length=64,verbose_name="udid唯一标识",db_index=True)
product = models.CharField(max_length=64, verbose_name="产品", blank=True, null=True, )
serial = models.CharField(max_length=64, verbose_name="序列号", blank=True, null=True, )
version = models.CharField(max_length=64, verbose_name="型号", blank=True, null=True, )
@ -205,6 +205,8 @@ class AppIOSDeveloperInfo(models.Model):
use_number = models.IntegerField(verbose_name="已消耗设备数",default=0)
created_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
updated_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")
description = models.TextField('备注', blank=True, null=True, default='')
class Meta:
verbose_name = '苹果开发者账户'
verbose_name_plural = "苹果开发者账户"

@ -25,6 +25,8 @@ from api.views.uploads import AppAnalyseView,UploadView
from api.views.storage import StorageView
from api.views.receiveudids import IosUDIDView
from api.views.supersign import DeveloperView,SuperSignUsedView,AppUDIDUsedView
# router=DefaultRouter()
# router.register("apps", AppsView)
@ -43,4 +45,7 @@ urlpatterns = [
re_path("^short/(?P<short>\w+)$", ShortDownloadView.as_view()),
re_path("^udid/(?P<short>\w+)$", IosUDIDView.as_view()),
re_path("^analyse$", AppAnalyseView.as_view()),
re_path("^supersign/developer$", DeveloperView.as_view()),
re_path("^supersign/devices$", SuperSignUsedView.as_view()),
re_path("^supersign/udid$", AppUDIDUsedView.as_view()),
]

@ -104,15 +104,14 @@ def get_redirect_server_domain(request):
class IosUtils(object):
def __init__(self, udid_info, app_obj):
def __init__(self, udid_info,user_obj,app_obj=None):
self.udid_info = udid_info
self.app_obj = app_obj
self.user_obj = app_obj.user_id
self.user_obj = user_obj
self.get_developer_auth()
def get_developer_auth(self):
developer_obj = AppIOSDeveloperInfo.objects.filter(user_id=self.user_obj, is_actived=True,
use_number__lte=F("usable_number")).first()
developer_obj = self.get_developer_user_by_app_udid()
auth = {
"username": developer_obj.email,
"password": developer_obj.password,
@ -121,6 +120,17 @@ class IosUtils(object):
self.developer_obj = developer_obj
self.auth = auth
def get_developer_user_by_app_udid(self):
usedeviceobj = APPSuperSignUsedInfo.objects.filter(udid__udid=self.udid_info.get('udid'), app_id=self.app_obj,
user_id=self.user_obj).first()
if usedeviceobj and usedeviceobj.developer_obj.use_number < usedeviceobj.developer_obj.usable_number:
developer_obj = usedeviceobj.developerid
else:
developer_obj = AppIOSDeveloperInfo.objects.filter(user_id=self.user_obj, is_actived=True,
use_number__lt=F("usable_number")).order_by(
"created_time").first()
return developer_obj
def create_cert(self):
app_api_obj = AppDeveloperApi(**self.auth)
app_api_obj.create_cert(self.user_obj)
@ -179,11 +189,25 @@ class IosUtils(object):
newdata = {
"is_signed": True,
"binary_file": random_file_name + ".ipa"
"binary_file": random_file_name
}
AppUDID.objects.filter(app_id=self.app_obj, udid=self.udid_info.get('udid')).update(**newdata)
APPSuperSignUsedInfo.objects.create(app_id=self.app_obj, user_id=self.user_obj, developerid=self.developer_obj,
udid=self.udid_info.get('udid'))
udid=AppUDID.objects.filter(app_id=self.app_obj,udid=self.udid_info.get('udid')).first())
AppIOSDeveloperInfo.objects.filter(user_id=self.user_obj, is_actived=True,
use_number__lte=F("usable_number")).first().update(
use_number=self.developer_obj.use_number + 1)
@staticmethod
def disable_udid(udid_obj,app_id):
usedeviceobj=APPSuperSignUsedInfo.objects.filter(udid=udid_obj,app_id_id=app_id)
if usedeviceobj:
developer_obj = usedeviceobj.first().developerid
auth = {
"username": developer_obj.email,
"password": developer_obj.password,
"certid": developer_obj.certid
}
app_api_obj = AppDeveloperApi(**auth)
app_api_obj.set_device_status("disable",udid_obj.udid)
usedeviceobj.delete()

@ -212,3 +212,52 @@ class StorageSerializer(serializers.ModelSerializer):
storage_obj = models.AppStorage.objects.create(**validated_data,user_id=user_obj,)
return storage_obj
return None
class DeveloperSerializer(serializers.ModelSerializer):
class Meta:
model = models.AppIOSDeveloperInfo
# depth = 1
exclude = ["password", "id","name","user_id"]
class SuperSignUsedSerializer(serializers.ModelSerializer):
class Meta:
model = models.APPSuperSignUsedInfo
# depth = 1
fields = ["created_time","device_udid","device_name","developer_id","bundle_id","bundle_name"]
device_udid = serializers.SerializerMethodField()
device_name = serializers.SerializerMethodField()
developer_id = serializers.SerializerMethodField()
bundle_id = serializers.SerializerMethodField()
bundle_name = serializers.SerializerMethodField()
def get_device_udid(self,obj):
return obj.udid.udid
def get_device_name(self,obj):
return obj.udid.product
def get_developer_id(self,obj):
return obj.developerid.email
def get_bundle_id(self, obj):
return obj.app_id.bundle_id
def get_bundle_name(self, obj):
return obj.app_id.name
class DeviceUDIDSerializer(serializers.ModelSerializer):
class Meta:
model = models.AppUDID
# depth = 1
exclude = ["binary_file","updated_time","is_signed"]
bundle_id = serializers.SerializerMethodField()
bundle_name = serializers.SerializerMethodField()
def get_bundle_id(self, obj):
return obj.app_id.bundle_id
def get_bundle_name(self, obj):
return obj.app_id.name

@ -20,7 +20,7 @@ class IosUDIDView(View):
if app_info :
if app_info.issupersign:
AppUDID.objects.update_or_create(app_id=app_info,**format_udid_info,defaults={'udid':format_udid_info.get('udid')})
ios_obj = IosUtils(format_udid_info,app_info)
ios_obj = IosUtils(format_udid_info,app_info.user_id,app_info)
ios_obj.resign()
else:
return Http404

@ -0,0 +1,93 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# project: 3月
# author: liuyu
# date: 2020/3/4
from rest_framework.views import APIView
from api.utils.response import BaseResponse
from api.utils.auth import ExpiringTokenAuthentication
from rest_framework.response import Response
from api.models import AppIOSDeveloperInfo,APPSuperSignUsedInfo,AppUDID
from api.utils.serializer import DeveloperSerializer, UserInfoSerializer,SuperSignUsedSerializer,DeviceUDIDSerializer
from rest_framework.pagination import PageNumberPagination
from api.utils.app.supersignutils import IosUtils
class AppsPageNumber(PageNumberPagination):
page_size = 10 # 每页显示多少条
page_size_query_param = 'size' # URL中每页显示条数的参数
page_query_param = 'page' # URL中页码的参数
max_page_size = None # 最大页码数限制
class DeveloperView(APIView):
authentication_classes = [ExpiringTokenAuthentication, ]
def get(self, request):
res = BaseResponse()
developer_obj = AppIOSDeveloperInfo.objects.filter(user_id=request.user)
page_obj = AppsPageNumber()
app_page_serializer = page_obj.paginate_queryset(queryset=developer_obj.order_by("-updated_time"), request=request,
view=self)
app_serializer = DeveloperSerializer(app_page_serializer, many=True,)
userserializer = UserInfoSerializer(request.user)
res.userinfo = {}
res.has_next = {}
res.userinfo = userserializer.data
res.data = app_serializer.data
res.has_next = page_obj.page.has_next()
return Response(res.dict)
class SuperSignUsedView(APIView):
authentication_classes = [ExpiringTokenAuthentication, ]
def get(self, request):
res = BaseResponse()
developer_obj = APPSuperSignUsedInfo.objects.filter(user_id=request.user)
page_obj = AppsPageNumber()
app_page_serializer = page_obj.paginate_queryset(queryset=developer_obj.order_by("-created_time"), request=request,
view=self)
app_serializer = SuperSignUsedSerializer(app_page_serializer, many=True, )
res.data = app_serializer.data
res.has_next = page_obj.page.has_next()
return Response(res.dict)
class AppUDIDUsedView(APIView):
authentication_classes = [ExpiringTokenAuthentication, ]
def get(self, request):
res = BaseResponse()
udid = request.query_params.get("udid", None)
bundleid = request.query_params.get("bundleid", None)
if udid and bundleid:
developer_obj = AppUDID.objects.filter(app_id__user_id_id=request.user,app_id__bundle_id=bundleid,udid=udid)
elif udid:
developer_obj = AppUDID.objects.filter(app_id__user_id_id=request.user,udid=udid)
elif bundleid:
developer_obj = AppUDID.objects.filter(app_id__user_id_id=request.user,app_id__bundle_id=bundleid)
else:
developer_obj = AppUDID.objects.filter(app_id__user_id_id=request.user)
page_obj = AppsPageNumber()
app_page_serializer = page_obj.paginate_queryset(queryset=developer_obj.order_by("-created_time"), request=request,
view=self)
app_serializer = DeviceUDIDSerializer(app_page_serializer, many=True,)
res.data = app_serializer.data
res.has_next = page_obj.page.has_next()
return Response(res.dict)
def delete(self,request):
res = BaseResponse()
id = request.query_params.get("id", None)
app_id = request.query_params.get("aid", None)
app_udid_obj=AppUDID.objects.filter(app_id__user_id_id=request.user,pk=id)
IosUtils.disable_udid(app_udid_obj.first(),app_id)
app_udid_obj.delete()
return self.get(request)

@ -39,7 +39,7 @@ class DevelopPortalHandle
if !cert then
cert = Spaceship::Portal.certificate.production.all.last
end
profile = provisioningClass.create!(bundle_id: appid,certificate:cert,name:provisionName + '_dis')
profile = provisioningClass.create!(bundle_id: appid,certificate:cert,name:provisionName.split("/")[-1])
return profile
end

Loading…
Cancel
Save