优化代码,增加证书信息展示功能,增加包重签功能

pull/37/head
nineven 3 years ago
parent cf9d9eeaf8
commit 5edf7cd65a
  1. 115
      fir_client/src/components/user/FirSuperSignBase.vue
  2. 7
      fir_ser/api/views/login_wx.py
  3. 8
      fir_ser/common/base/magic.py
  4. 4
      fir_ser/common/libs/apple/appleapiv3.py
  5. 5
      fir_ser/common/libs/mp/wechat.py
  6. 10
      fir_ser/xsign/tasks.py
  7. 16
      fir_ser/xsign/utils/iossignapi.py
  8. 66
      fir_ser/xsign/utils/supersignutils.py
  9. 33
      fir_ser/xsign/views/supersign.py

@ -106,7 +106,7 @@
<el-form-item label="维护模式" label-width="110px" style="text-align: left"> <el-form-item label="维护模式" label-width="110px" style="text-align: left">
<el-switch <el-switch
v-model="read_only_mode" v-model="read_only_mode"
:disabled="read_only_mode==='on'" :disabled="editdeveloperinfo.status !== 1"
active-color="#13ce66" active-color="#13ce66"
active-value="on" active-value="on"
inactive-color="#ff4949" inactive-color="#ff4949"
@ -145,6 +145,9 @@
<el-button v-if="isedit && editdeveloperinfo.certid" size="small" <el-button v-if="isedit && editdeveloperinfo.certid" size="small"
@click="exportcert">导出证书 @click="exportcert">导出证书
</el-button> </el-button>
<el-button v-if="isedit && editdeveloperinfo.status!==0 || editdeveloperinfo.certid" size="small"
@click="checkcert">证书检测
</el-button>
<el-button v-if="isedit && !editdeveloperinfo.certid" size="small" <el-button v-if="isedit && !editdeveloperinfo.certid" size="small"
@click="importcertDeveloperVisible=true">导入p12证书 @click="importcertDeveloperVisible=true">导入p12证书
</el-button> </el-button>
@ -325,6 +328,68 @@
</el-row> </el-row>
</div> </div>
</el-dialog> </el-dialog>
<el-dialog :close-on-click-modal="false" :destroy-on-close="true" :visible.sync="certinfovisible"
center title="苹果开发证书信息" width="750px">
<el-tag style="margin: 10px">期望的证书ID{{ editdeveloperinfo.certid }}</el-tag>
<el-tag v-if="certinfo_err" style="margin: 10px" type="danger">{{ certinfo_err }}</el-tag>
<el-table
v-loading="loading"
:data="certinfo"
border
stripe
style="width: 100%">
<el-table-column
align="center"
label="证书ID"
prop="certid"
>
<template slot-scope="scope">
<el-popover placement="top" trigger="hover">
<p>证书ID: {{ scope.row.certid }}</p>
<p>证书序列号: {{ scope.row.serial_number }}</p>
<p>证书平台: {{ scope.row.platform }}</p>
<p>证书名称: {{ scope.row.name }}</p>
<p>证书显示名字: {{ scope.row.display_name }}</p>
<div slot="reference" class="name-wrapper">
<el-tag>{{ scope.row.certid }}</el-tag>
</div>
</el-popover>
</template>
</el-table-column>
<el-table-column
align="center"
label="证书类型"
prop="c_type"
>
</el-table-column>
<el-table-column
align="center"
label="是否本属于本平台"
prop="c_type"
>
<template slot-scope="scope">
<el-tag v-if="scope.row.exist">属于</el-tag>
<el-tag v-else type="info">
其他
</el-tag>
</template>
</el-table-column>
<el-table-column
:formatter="formatter"
align="center"
label="到期时间"
prop="expire"
width="160">
</el-table-column>
</el-table>
<span slot="footer">
<el-button @click="certinfovisible=false,certinfo=[]">关闭</el-button>
</span>
</el-dialog>
<el-tabs v-model="activeName" tab-position="top" type="border-card" @tab-click="handleClick"> <el-tabs v-model="activeName" tab-position="top" type="border-card" @tab-click="handleClick">
@ -519,6 +584,7 @@
align="center" align="center"
label="设备消耗" label="设备消耗"
prop="use_number" prop="use_number"
sortable
width="60"> width="60">
<template slot-scope="scope"> <template slot-scope="scope">
<el-popover placement="top" trigger="hover"> <el-popover placement="top" trigger="hover">
@ -535,6 +601,7 @@
align="center" align="center"
label="应用签名" label="应用签名"
prop="app_used_count" prop="app_used_count"
sortable
width="60"> width="60">
<template slot-scope="scope"> <template slot-scope="scope">
@ -555,7 +622,8 @@
<el-table-column <el-table-column
align="center" align="center"
label="专属账户" label="专属账户"
prop="is_private" prop="app_private_number"
sortable
width="60"> width="60">
<template slot-scope="scope"> <template slot-scope="scope">
<el-popover placement="top" <el-popover placement="top"
@ -579,6 +647,7 @@
align="center" align="center"
label="自动检测" label="自动检测"
prop="auto_check" prop="auto_check"
sortable
width="60"> width="60">
<template slot-scope="scope"> <template slot-scope="scope">
<el-tag v-if="scope.row.auto_check" size="medium"></el-tag> <el-tag v-if="scope.row.auto_check" size="medium"></el-tag>
@ -598,6 +667,7 @@
align="center" align="center"
label="证书到期时间" label="证书到期时间"
prop="cert_expire_time" prop="cert_expire_time"
sortable
width="100"> width="100">
</el-table-column> </el-table-column>
<el-table-column <el-table-column
@ -985,6 +1055,11 @@
<p>开发者ID: {{ get_developer_uid(scope.row.issuer_id) }}</p> <p>开发者ID: {{ get_developer_uid(scope.row.issuer_id) }}</p>
<p>开发者备注: {{ scope.row.developer_description }}</p> <p>开发者备注: {{ scope.row.developer_description }}</p>
<p>开发者状态: {{ scope.row.developer_status }}</p> <p>开发者状态: {{ scope.row.developer_status }}</p>
<p>安装异常???
<el-button :disabled="scope.row.developer_status!=='已激活'" size="small" @click="resign(scope.row)">
尝试重新签包
</el-button>
</p>
<div slot="reference" class="name-wrapper"> <div slot="reference" class="name-wrapper">
<span>{{ get_developer_uid(scope.row.issuer_id) }}</span> <span>{{ get_developer_uid(scope.row.issuer_id) }}</span>
</div> </div>
@ -1315,6 +1390,9 @@ export default {
components: {AppleDeveloperBindApp}, components: {AppleDeveloperBindApp},
data() { data() {
return { return {
certinfovisible: false,
certinfo: [],
certinfo_err: '',
dialogShowDeviceBillInfo: false, dialogShowDeviceBillInfo: false,
currentudid: '', currentudid: '',
balance_info: {all_balance: 0, used_balance: 0}, balance_info: {all_balance: 0, used_balance: 0},
@ -1692,6 +1770,18 @@ export default {
return '#F50346'; return '#F50346';
} }
}, },
resign(row_info) {
let other_uid = row_info.other_uid
let uid = ''
if (other_uid && other_uid.uid) {
uid = other_uid.uid
}
this.iosdevicesudidFun('POST', {
id: row_info.id,
aid: row_info.app_id,
uid: uid
}, null)
},
udidDeleteFun(scope, disabled) { udidDeleteFun(scope, disabled) {
this.$confirm('此操作会禁用该苹果开发者账户下面的该设备,可能会导致超级签包的闪退, 是否继续?', '警告', { this.$confirm('此操作会禁用该苹果开发者账户下面的该设备,可能会导致超级签包的闪退, 是否继续?', '警告', {
confirmButtonText: '确定', confirmButtonText: '确定',
@ -1768,6 +1858,12 @@ export default {
developercert(data => { developercert(data => {
}, {methods: 'FILE', data: {issuer_id: this.editdeveloperinfo.issuer_id}}) }, {methods: 'FILE', data: {issuer_id: this.editdeveloperinfo.issuer_id}})
}, },
checkcert() {
this.iosdeveloperFun({
"methods": "PUT",
"data": {"issuer_id": this.editdeveloperinfo.issuer_id, "act": 'checkcert'}
});
},
isorenewcert(act) { isorenewcert(act) {
this.$confirm('此操作将永久删除该发布证书, 建议先导出证书。是否继续删除?', '提示', { this.$confirm('此操作将永久删除该发布证书, 建议先导出证书。是否继续删除?', '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
@ -1943,7 +2039,7 @@ export default {
} else { } else {
this.loading = true this.loading = true
} }
if (params.methods === 'PUT') { if (params.methods === 'PUT' && params.data.act !== 'checkcert') {
params.data.size = this.pagination.pagesize params.data.size = this.pagination.pagesize
params.data.page = this.pagination.currentPage params.data.page = this.pagination.currentPage
} }
@ -1973,6 +2069,13 @@ export default {
this.setdeveloperstatusVisible = false this.setdeveloperstatusVisible = false
this.change_developer_status = '' this.change_developer_status = ''
} }
if (params.data.act === 'checkcert') {
this.certinfo = data.data.cert_info;
this.certinfo_err = data.data.return_info;
this.loadingfun.close();
this.certinfovisible = true
return
}
if (this.dialogaddDeveloperVisible) { if (this.dialogaddDeveloperVisible) {
this.canceledit(); this.canceledit();
this.$message.success("操作成功"); this.$message.success("操作成功");
@ -2071,13 +2174,15 @@ export default {
} }
iosdevicesudid(data => { iosdevicesudid(data => {
if (data.code === 1000) { if (data.code === 1000) {
if (action !== "DELETE") { if (action === "GET") {
this.app_udid_lists = data.data; this.app_udid_lists = data.data;
this.pagination.total = data.count; this.pagination.total = data.count;
} else { } else if (action === "DELETE") {
if (scope) { if (scope) {
this.app_udid_lists = removeAaary(this.app_udid_lists, scope.row) this.app_udid_lists = removeAaary(this.app_udid_lists, scope.row)
} }
} else if (action === 'POST') {
this.$message.success("操作成功");
} }
} else { } else {
this.$message.error("操作失败了 " + data.msg); this.$message.error("操作失败了 " + data.msg);

@ -1,5 +1,6 @@
import logging import logging
from django.http import HttpResponse
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.views import APIView from rest_framework.views import APIView
@ -134,13 +135,13 @@ class WeChatWebLoginView(APIView):
'openid': wx_user_info.get('openid'), 'openid': wx_user_info.get('openid'),
'nickname': wx_user_info.get('nickname'), 'nickname': wx_user_info.get('nickname'),
'sex': wx_user_info.get('sex'), 'sex': wx_user_info.get('sex'),
'subscribe_time': wx_user_info.get('subscribe_time', 0), # 'subscribe_time': wx_user_info.get('subscribe_time', 0),
'head_img_url': wx_user_info.get('headimgurl', ''), 'head_img_url': wx_user_info.get('headimgurl', ''),
'address': f"{wx_user_info.get('country')}-{wx_user_info.get('province')}-{wx_user_info.get('city')}", 'address': f"{wx_user_info.get('country')}-{wx_user_info.get('province')}-{wx_user_info.get('city')}",
'subscribe': wx_user_info.get('subscribe', 0), # 'subscribe': wx_user_info.get('subscribe', 0),
} }
logger.info(f'{wx_user_info}') logger.info(f'{wx_user_info}')
ThirdWeChatUserInfo.objects.filter(openid=wx_user_info.get('openid')).update(**wx_user_info) ThirdWeChatUserInfo.objects.filter(openid=wx_user_info.get('openid')).update(**wx_user_info)
return Response('更新成功') return HttpResponse('<h2>更新成功</h2>')
ret.data = wx_login_obj.make_auth_uri() ret.data = wx_login_obj.make_auth_uri()
return Response(ret.dict) return Response(ret.dict)

@ -64,3 +64,11 @@ def call_function_try_attempts(try_attempts=3, sleep_time=2, failed_callback=Non
return wrapper return wrapper
return decorator return decorator
def magic_wrapper(func, *args, **kwargs):
@wraps(func)
def wrapper():
return func(*args, **kwargs)
return wrapper

@ -870,8 +870,8 @@ class AppStoreConnectApi(DevicesAPI, BundleIDsAPI, BundleIDsCapabilityAPI, Profi
return self.__profile_store(req) return self.__profile_store(req)
@call_function_try_attempts(try_attempts=2) @call_function_try_attempts(try_attempts=2)
def get_all_certificates(self): def get_all_certificates(self, query_parameters=None):
req = self.list_certificate() req = self.list_certificate(query_parameters)
return self.__certificates_store(req) return self.__certificates_store(req)
@call_function_try_attempts() @call_function_try_attempts()

@ -27,6 +27,7 @@ def format_req_json(j_data, func, *args, **kwargs):
if not status: if not status:
return result return result
return func(*args, **kwargs)[1] return func(*args, **kwargs)[1]
logger.info(f'j_data:{j_data}')
return j_data return j_data
@ -174,6 +175,8 @@ class WxMsgCrypt(WxMsgCryptBase):
class WxTemplateMsg(object): class WxTemplateMsg(object):
def send_msg(self, to_user, template_id, content): def send_msg(self, to_user, template_id, content):
if not Config.THIRDLOGINCONF.get('active'):
return False, f'weixin status is disabled'
msg_uri = f'https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={get_wx_access_token_cache()}' msg_uri = f'https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={get_wx_access_token_cache()}'
data = { data = {
"touser": to_user, "touser": to_user,
@ -184,7 +187,7 @@ class WxTemplateMsg(object):
} }
req = requests.post(msg_uri, json=data) req = requests.post(msg_uri, json=data)
if req.status_code == 200: if req.status_code == 200:
return True, format_req_json(req.json(), get_userinfo_from_openid, to_user) return True, format_req_json(req.json(), self.send_msg, to_user, template_id, content)
logger.error(f"send msg from openid failed {req.status_code} {req.text}") logger.error(f"send msg from openid failed {req.status_code} {req.text}")
return False, req.text return False, req.text

@ -48,12 +48,18 @@ def run_sign_task(format_udid_info, short, client_ip):
return msg return msg
def run_resign_task(app_id, need_download_profile=True, force=True): def run_resign_task(app_id, need_download_profile=True, force=True, developers_filter=None):
if developers_filter is None:
developers_filter = []
app_obj = Apps.objects.filter(pk=app_id).first() app_obj = Apps.objects.filter(pk=app_id).first()
if app_obj.issupersign and app_obj.user_id.supersign_active: if app_obj.issupersign and app_obj.user_id.supersign_active:
developer_app_id_queryset = DeveloperAppID.objects.filter(app_id=app_obj)
if developers_filter:
developer_app_id_queryset = developer_app_id_queryset.filter(developerid__in=developers_filter)
with cache.lock("%s_%s" % ('task_resign', app_obj.app_id), timeout=60 * 60): with cache.lock("%s_%s" % ('task_resign', app_obj.app_id), timeout=60 * 60):
task_list = [] task_list = []
for developer_app_id_obj in DeveloperAppID.objects.filter(app_id=app_obj).all(): for developer_app_id_obj in developer_app_id_queryset.all():
c_task = run_resign_task_do.apply_async((app_id, developer_app_id_obj.developerid.pk, c_task = run_resign_task_do.apply_async((app_id, developer_app_id_obj.developerid.pk,
developer_app_id_obj.aid, need_download_profile, force)) developer_app_id_obj.aid, need_download_profile, force))
task_list.append(c_task) task_list.append(c_task)

@ -254,7 +254,7 @@ class AppDeveloperApiV2(object):
attr = object.__getattribute__(self, name) attr = object.__getattribute__(self, name)
if hasattr(attr, '__call__'): if hasattr(attr, '__call__'):
def func(*args, **kwargs): def func(*args, **kwargs):
if attr.__name__ in ['active', 'get_device', '__result_format', '__callback_run']: if attr.__name__ in ['get_developer_cert_info', 'get_device', '__result_format', '__callback_run']:
return attr(*args, **kwargs) return attr(*args, **kwargs)
else: else:
if AppIOSDeveloperInfo.objects.filter(pk=self.developer_pk, if AppIOSDeveloperInfo.objects.filter(pk=self.developer_pk,
@ -313,14 +313,14 @@ class AppDeveloperApiV2(object):
logger.warning( logger.warning(
f'issuer_id:{self.issuer_id} {callback_info}-{failed_call_prefix} is running') f'issuer_id:{self.issuer_id} {callback_info}-{failed_call_prefix} is running')
def active(self): def get_developer_cert_info(self, query_parameters=None):
""" """
:return: 结果为空列表或者是 object 或者是 [object,object] 其他为 false :return: 结果为空列表或者是 object 或者是 [object,object] 其他为 false
""" """
result = {} result = {}
try: try:
apple_obj = AppStoreConnectApi(self.issuer_id, self.private_key_id, self.p8key) apple_obj = AppStoreConnectApi(self.issuer_id, self.private_key_id, self.p8key)
certificates = apple_obj.get_all_certificates() certificates = apple_obj.get_all_certificates(query_parameters)
return self.__result_format(certificates, Certificates) return self.__result_format(certificates, Certificates)
except Exception as e: except Exception as e:
logger.error(f"issuer_id:{self.issuer_id} ios developer active Failed Exception:{e}") logger.error(f"issuer_id:{self.issuer_id} ios developer active Failed Exception:{e}")
@ -392,16 +392,18 @@ class AppDeveloperApiV2(object):
cer = load_certificate(FILETYPE_PEM, open(app_dev_pem, 'rb').read()) cer = load_certificate(FILETYPE_PEM, open(app_dev_pem, 'rb').read())
not_after = datetime.datetime.strptime(cer.get_notAfter().decode('utf-8'), "%Y%m%d%H%M%SZ") not_after = datetime.datetime.strptime(cer.get_notAfter().decode('utf-8'), "%Y%m%d%H%M%SZ")
apple_obj = AppStoreConnectApi(self.issuer_id, self.private_key_id, self.p8key) apple_obj = AppStoreConnectApi(self.issuer_id, self.private_key_id, self.p8key)
certificates = apple_obj.get_all_certificates() certificates = apple_obj.get_all_certificates({'filter[certificateType]': 'IOS_DISTRIBUTION'})
status, result = self.__result_format(certificates, Certificates) status, result = self.__result_format(certificates, Certificates)
if status: if status:
for cert_obj in result: for cert_obj in result:
f_date = format_apple_date(cert_obj.expirationDate) f_date = format_apple_date(cert_obj.expirationDate)
logger.info( logger.info(
f"issuer_id:{self.issuer_id} {cert_obj.id}-{not_after.timestamp()} - {f_date.timestamp()} ") f"issuer_id:{self.issuer_id} {cert_obj.id}-{not_after.timestamp()} - {f_date.timestamp()} - {cer.get_serial_number()} - {cert_obj.serialNumber} ")
if not_after.timestamp() == f_date.timestamp(): # if not_after.timestamp() == f_date.timestamp(): # 比较证书的序列号来判断是否为同一个证书
if cer.get_serial_number() == int(cert_obj.serialNumber, 16):
return True, cert_obj return True, cert_obj
raise Exception(str(certificates)) result = {}
raise Exception(str('证书不匹配,请更换其他开发证书重新导入'))
except Exception as e: except Exception as e:
logger.error(f"issuer_id:{self.issuer_id} ios developer cert {app_dev_pem} auto get Failed Exception:{e}") logger.error(f"issuer_id:{self.issuer_id} ios developer cert {app_dev_pem} auto get Failed Exception:{e}")
result['return_info'] = check_error_call_back(str(e), self.developer_pk) result['return_info'] = check_error_call_back(str(e), self.developer_pk)

@ -9,7 +9,6 @@ import os
import time import time
import uuid import uuid
import zipfile import zipfile
from functools import wraps
import xmltodict import xmltodict
from django.core.cache import cache from django.core.cache import cache
@ -20,7 +19,7 @@ from api.utils.response import BaseResponse
from api.utils.utils import delete_local_files, download_files_form_oss from api.utils.utils import delete_local_files, download_files_form_oss
from common.base.baseutils import file_format_path, delete_app_profile_file, get_profile_full_path, format_apple_date, \ from common.base.baseutils import file_format_path, delete_app_profile_file, get_profile_full_path, format_apple_date, \
get_format_time, make_app_uuid, make_from_user_uuid get_format_time, make_app_uuid, make_from_user_uuid
from common.base.magic import run_function_by_locker, call_function_try_attempts from common.base.magic import run_function_by_locker, call_function_try_attempts, magic_wrapper
from common.cache.state import CleanErrorBundleIdSignDataState from common.cache.state import CleanErrorBundleIdSignDataState
from common.core.sysconfig import Config from common.core.sysconfig import Config
from common.utils.caches import del_cache_response_by_short, send_msg_over_limit, check_app_permission, \ from common.utils.caches import del_cache_response_by_short, send_msg_over_limit, check_app_permission, \
@ -214,14 +213,6 @@ def get_apple_udid_key(auth):
return m_key return m_key
def err_callback(func, *args, **kwargs):
@wraps(func)
def wrapper():
return func(*args, **kwargs)
return wrapper
def disable_developer_and_send_email(app_obj, developer_obj): def disable_developer_and_send_email(app_obj, developer_obj):
logger.error(f"app {app_obj} developer {developer_obj} sign failed. so disabled") logger.error(f"app {app_obj} developer {developer_obj} sign failed. so disabled")
developer_obj.status = 5 developer_obj.status = 5
@ -579,7 +570,7 @@ class IosUtils(object):
register_failed_callback = [ register_failed_callback = [
{ {
'func_list': [err_callback(IosUtils.get_device_from_developer, developer_obj)], 'func_list': [magic_wrapper(IosUtils.get_device_from_developer, developer_obj)],
'err_match_msg': [ 'err_match_msg': [
"There are no current ios devices", "There are no current ios devices",
"Your development team has reached the maximum number of registered iPhone devices" "Your development team has reached the maximum number of registered iPhone devices"
@ -588,14 +579,14 @@ class IosUtils(object):
] ]
set_failed_callback = [ set_failed_callback = [
{ {
'func_list': [err_callback(IosUtils.get_device_from_developer, developer_obj)], 'func_list': [magic_wrapper(IosUtils.get_device_from_developer, developer_obj)],
'err_match_msg': [ 'err_match_msg': [
"There are no current ios devices", "There are no current ios devices",
"Device obj is None" "Device obj is None"
] ]
}, },
{ {
'func_list': [err_callback(IosUtils.check_device_status, developer_obj)], 'func_list': [magic_wrapper(IosUtils.check_device_status, developer_obj)],
'err_match_msg': [ 'err_match_msg': [
"ENTITY_ERROR.ATTRIBUTE.INVALID.DUPLICATE", "ENTITY_ERROR.ATTRIBUTE.INVALID.DUPLICATE",
] ]
@ -672,7 +663,7 @@ class IosUtils(object):
failed_callback = [] failed_callback = []
failed_callback.extend([ failed_callback.extend([
{ {
'func_list': [err_callback(IosUtils.clean_super_sign_things_by_app_obj, app_obj, developer_obj)], 'func_list': [magic_wrapper(IosUtils.clean_super_sign_things_by_app_obj, app_obj, developer_obj)],
'err_match_msg': ["There is no App ID with ID"] 'err_match_msg': ["There is no App ID with ID"]
} }
]) ])
@ -719,15 +710,15 @@ class IosUtils(object):
failed_callback.extend([ failed_callback.extend([
{ {
'func_list': [err_callback(IosUtils.clean_super_sign_things_by_app_obj, app_obj, developer_obj)], 'func_list': [magic_wrapper(IosUtils.clean_super_sign_things_by_app_obj, app_obj, developer_obj)],
'err_match_msg': ["There is no App ID with ID"] 'err_match_msg': ["There is no App ID with ID"]
}, },
{ {
'func_list': [err_callback(IosUtils.active_developer, developer_obj, True)], 'func_list': [magic_wrapper(IosUtils.active_developer, developer_obj)],
'err_match_msg': ["There are no current certificates on this team matching the provided certificate"] 'err_match_msg': ["There are no current certificates on this team matching the provided certificate"]
}, },
{ {
'func_list': [err_callback(IosUtils.check_device_status, developer_obj)], 'func_list': [magic_wrapper(IosUtils.check_device_status, developer_obj)],
'err_match_msg': ["There are no current ios devices on this team matching the provided device IDs"] 'err_match_msg': ["There are no current ios devices on this team matching the provided device IDs"]
} }
]) ])
@ -1052,6 +1043,43 @@ class IosUtils(object):
except Exception as e: except Exception as e:
return False, {'err_info': str(e)} return False, {'err_info': str(e)}
@staticmethod
def get_developer_cert_info(developer_obj):
"""
获取开发者证书信息
:param developer_obj:
:return:
"""
app_api_obj = get_api_obj(developer_obj)
# status, result = app_api_obj.get_developer_cert_info({'filter[certificateType]': 'IOS_DISTRIBUTION'})
status, result = app_api_obj.get_developer_cert_info()
if status:
cert_info = []
cert_is_exists = True
for cert_obj in result:
c_info = {
'certid': cert_obj.id,
'serial_number': cert_obj.serialNumber,
'name': cert_obj.name,
'display_name': cert_obj.displayName,
'platform': cert_obj.platform,
'cert_expire_time': format_apple_date(cert_obj.expirationDate),
'c_type': cert_obj.certificateType,
'exist': False}
if cert_obj.id == developer_obj.certid and cert_is_exists:
developer_obj.cert_expire_time = format_apple_date(cert_obj.expirationDate)
cert_is_exists = False
c_info['exist'] = True
cert_info.append(c_info)
cert_info.sort(key=lambda x: x['exist'] == False)
if developer_obj.certid and len(developer_obj.certid) > 3 and cert_is_exists and len(result) > 0:
# 多次判断数据库证书id和苹果开发id不一致,可认为被用户删掉,需要执行清理开发者操作
return status, {'return_info': '证书异常,苹果开发者证书与平台记录ID不一致', 'cert_info': cert_info}
if developer_obj.certid and len(developer_obj.certid) > 3 and len(result) == 0:
return status, {'return_info': '证书异常,苹果开发者证书为空,疑似证书在苹果开发平台被删除', 'cert_info': cert_info}
return status, {'cert_info': cert_info}
return status, result
@staticmethod @staticmethod
def active_developer(developer_obj, auto_clean=True, loop_count=1): def active_developer(developer_obj, auto_clean=True, loop_count=1):
""" """
@ -1062,7 +1090,7 @@ class IosUtils(object):
:return: :return:
""" """
app_api_obj = get_api_obj(developer_obj) app_api_obj = get_api_obj(developer_obj)
status, result = app_api_obj.active() status, result = app_api_obj.get_developer_cert_info({'filter[certificateType]': 'IOS_DISTRIBUTION'})
if status: if status:
cert_is_exists = True cert_is_exists = True
for cert_obj in result: for cert_obj in result:
@ -1091,6 +1119,8 @@ class IosUtils(object):
f"{developer_obj} loop check developer cert.auto_clean:{auto_clean} loop_count:{loop_count}") f"{developer_obj} loop check developer cert.auto_clean:{auto_clean} loop_count:{loop_count}")
return IosUtils.active_developer(developer_obj, auto_clean, loop_count) return IosUtils.active_developer(developer_obj, auto_clean, loop_count)
if developer_obj.certid and len(developer_obj.certid) > 3 and len(result) == 0:
return False, {'return_info': '证书异常,苹果开发者证书为空,疑似证书在苹果开发平台被删除'}
developer_obj.save(update_fields=['certid', 'cert_expire_time', 'status']) developer_obj.save(update_fields=['certid', 'cert_expire_time', 'status'])
return status, result return status, result

@ -23,7 +23,7 @@ from common.utils.download import get_app_download_url
from xsign.models import AppIOSDeveloperInfo, APPSuperSignUsedInfo, AppUDID, IosDeveloperPublicPoolBill, \ from xsign.models import AppIOSDeveloperInfo, APPSuperSignUsedInfo, AppUDID, IosDeveloperPublicPoolBill, \
UDIDsyncDeveloper, AppleDeveloperToAppUse, DeveloperAppID, APPToDeveloper, DeveloperDevicesID, \ UDIDsyncDeveloper, AppleDeveloperToAppUse, DeveloperAppID, APPToDeveloper, DeveloperDevicesID, \
IosDeveloperBill IosDeveloperBill
from xsign.tasks import run_resign_task_do from xsign.tasks import run_resign_task_do, run_resign_task
from xsign.utils.modelutils import get_user_public_used_sign_num, get_user_public_sign_num, check_uid_has_relevant, \ from xsign.utils.modelutils import get_user_public_used_sign_num, get_user_public_sign_num, check_uid_has_relevant, \
get_developer_devices get_developer_devices
from xsign.utils.serializer import DeveloperSerializer, SuperSignUsedSerializer, DeviceUDIDSerializer, \ from xsign.utils.serializer import DeveloperSerializer, SuperSignUsedSerializer, DeviceUDIDSerializer, \
@ -145,6 +145,15 @@ class DeveloperView(APIView):
res.code = 1008 res.code = 1008
res.msg = result.get("return_info") res.msg = result.get("return_info")
return Response(res.dict) return Response(res.dict)
elif act == "checkcert":
if developer_obj.certid:
status, result = IosUtils.get_developer_cert_info(developer_obj)
if status:
res.data = result
else:
res.code = 1008
res.msg = result.get("return_info")
return Response(res.dict)
elif act in ["renewcert", "cleancert"]: elif act in ["renewcert", "cleancert"]:
if developer_obj.certid: if developer_obj.certid:
# clean developer somethings. remove profile and revoke cert # clean developer somethings. remove profile and revoke cert
@ -408,6 +417,24 @@ class AppUDIDUsedView(APIView):
res.msg = '数据异常,删除失败' res.msg = '数据异常,删除失败'
return Response(res.dict) return Response(res.dict)
def post(self, request):
res = BaseResponse()
pk = request.data.get("id", None)
other_uid = request.data.get("uid", None)
app_id = request.data.get("aid", None)
app_udid_obj = AppUDID.objects.filter(pk=pk, app_id__user_id=request.user)
if not app_udid_obj and check_uid_has_relevant(request.user.uid, other_uid):
app_udid_obj = AppUDID.objects.filter(pk=pk, app_id__user_id__uid=other_uid)
if app_udid_obj:
super_sign_used_obj = APPSuperSignUsedInfo.objects.filter(udid=app_udid_obj.first()).first()
if super_sign_used_obj:
run_resign_task(app_id, need_download_profile=True, force=True,
developers_filter=[super_sign_used_obj.developerid])
else:
res.code = 10003
res.msg = '数据异常,重签名失败'
return Response(res.dict)
class DeveloperDeviceView(APIView): class DeveloperDeviceView(APIView):
authentication_classes = [ExpiringTokenAuthentication, ] authentication_classes = [ExpiringTokenAuthentication, ]
@ -491,12 +518,12 @@ class SuperSignCertView(APIView):
status, result = resign_app_obj.make_cert_from_p12(request.data.get('cert_pwd', ''), status, result = resign_app_obj.make_cert_from_p12(request.data.get('cert_pwd', ''),
request.data.get('cert_content', None)) request.data.get('cert_content', None))
if status: if status:
status, result = IosUtils.auto_get_cert_id_by_p12(developer_obj, request.user) status, _ = IosUtils.auto_get_cert_id_by_p12(developer_obj, request.user)
if status: if status:
resign_app_obj.write_cert() resign_app_obj.write_cert()
else: else:
res.code = 1003 res.code = 1003
res.msg = '证书未在开发者账户找到,请检查推送证书是否属于该开发者' res.msg = '证书未在开发者账户找到,请检查证书是否属于该开发者'
else: else:
res.code = 1002 res.code = 1002
res.msg = str(result['err_info']) res.msg = str(result['err_info'])

Loading…
Cancel
Save