签名优化

qrnn
youngS 3 years ago
parent 6412e36d0b
commit 341cf21367
  1. 23
      fir_client/src/components/user/FirSuperSignBase.vue
  2. 31
      fir_ser/api/tasks.py
  3. 97
      fir_ser/api/utils/app/supersignutils.py
  4. 44
      fir_ser/api/utils/apple/appleapiv3.py
  5. 3
      fir_ser/api/utils/modelutils.py
  6. 19
      fir_ser/api/views/apps.py
  7. 1
      fir_ser/api/views/supersign.py
  8. 8
      fir_ser/api/views/uploads.py

@ -180,7 +180,7 @@
clearable
placeholder="输入开发者用户ID"
style="width: 30%;margin-right: 30px;margin-bottom: 10px"/>
<el-button icon="el-icon-search" type="primary" @click="handleCurrentChange(pagination.currentPage)">
<el-button icon="el-icon-search" type="primary" @click="handleCurrentChange(1)">
搜索
</el-button>
<div style="width: 43%;margin-right: 30px;float:right">
@ -401,7 +401,7 @@
clearable
placeholder="输入开发者用户ID"
style="width: 30%;margin-right: 30px;margin-bottom: 10px"/>
<el-button icon="el-icon-search" type="primary" @click="handleCurrentChange(pagination.currentPage)">
<el-button icon="el-icon-search" type="primary" @click="handleCurrentChange(1)">
搜索
</el-button>
<el-button @click="syncalldevices">
@ -444,6 +444,17 @@
prop="version"
width="200">
</el-table-column>
<el-table-column
align="center"
label="设备状态"
width="110">
<template slot-scope="scope">
<el-tag v-if="!scope.row.status" type="info">禁用</el-tag>
<el-tag v-else>
启用
</el-tag>
</template>
</el-table-column>
<el-table-column
align="center"
label="开发者ID"
@ -471,7 +482,7 @@
clearable
placeholder="输入用户ID"
style="width: 23%;margin-right: 30px;margin-bottom: 10px"/>
<el-button icon="el-icon-search" type="primary" @click="handleCurrentChange(pagination.currentPage)">
<el-button icon="el-icon-search" type="primary" @click="handleCurrentChange(1)">
搜索
</el-button>
@ -540,7 +551,7 @@
clearable
placeholder="输入BundleID"
style="width: 30%;margin-right: 30px;margin-bottom: 10px"/>
<el-button icon="el-icon-search" type="primary" @click="handleCurrentChange(pagination.currentPage)">
<el-button icon="el-icon-search" type="primary" @click="handleCurrentChange(1)">
搜索
</el-button>
@ -634,7 +645,7 @@
placeholder="输入UDID"
style="width: 30%;margin-right: 30px;margin-bottom: 10px"/>
<el-button icon="el-icon-search" type="primary" @click="handleCurrentChange(pagination.currentPage)">
<el-button icon="el-icon-search" type="primary" @click="handleCurrentChange(1)">
搜索
</el-button>
<div style="width: 40%;margin-right: 30px;float:right">
@ -1125,7 +1136,7 @@ export default {
if (this.balance_info.all_balance - this.balance_info.used_balance < 0) {
this.bill_percent = 100;
} else {
this.bill_percent = Number(this.balance_info.used_balance * 100 / this.balance_info.all_balance);
this.bill_percent = parseInt(this.balance_info.used_balance * 100 / this.balance_info.all_balance);
}
}
}

@ -4,11 +4,13 @@
# author: NinEveN
# date: 2021/5/27
import logging
from celery import shared_task
from django.core.cache import cache
from api.models import Apps
from api.utils.app.supersignutils import IosUtils, resign_by_app_id
from api.models import Apps, DeveloperAppID
from api.utils.app.supersignutils import IosUtils, resign_by_app_id_and_developer
from api.utils.crontab.ctasks import sync_download_times, auto_clean_upload_tmp_file, auto_delete_ios_mobile_tmp_file, \
auto_check_ios_developer_active
from api.utils.geetest.geetest_utils import check_bypass_status
@ -18,6 +20,8 @@ from api.views.login import get_login_type
from fir_ser.celery import app
from fir_ser.settings import LOGIN, CHANGER, REGISTER
logger = logging.getLogger(__name__)
@shared_task
def run_sign_task(format_udid_info, short, client_ip):
@ -43,11 +47,26 @@ def run_sign_task(format_udid_info, short, client_ip):
return msg
@shared_task
def run_resign_task(app_id, need_download_profile=True, force=True):
app_obj = Apps.objects.filter(app_id=app_id).first()
with cache.lock("%s_%s" % ('task_resign', app_id), timeout=60 * 60):
return resign_by_app_id(app_obj, need_download_profile, force)
app_obj = Apps.objects.filter(pk=app_id).first()
if app_obj.issupersign and app_obj.user_id.supersign_active:
with cache.lock("%s_%s" % ('task_resign', app_obj.app_id), timeout=60 * 60):
task_list = []
for developer_app_id_obj in DeveloperAppID.objects.filter(app_id=app_obj).all():
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))
task_list.append(c_task)
for c_task in task_list:
msg = c_task.get(propagate=False)
logger.info(f"app {app_obj} run_resign_task msg:{msg}")
if c_task.successful():
c_task.forget()
return True
@shared_task
def run_resign_task_do(app_id, developer_id, developer_app_id, need_download_profile=True, force=True):
return resign_by_app_id_and_developer(app_id, developer_id, developer_app_id, need_download_profile, force)
@app.task

@ -15,7 +15,7 @@ import xmltodict
from django.core.cache import cache
from api.models import APPSuperSignUsedInfo, AppUDID, AppIOSDeveloperInfo, AppReleaseInfo, Apps, APPToDeveloper, \
UDIDsyncDeveloper, DeveloperAppID, DeveloperDevicesID, IosDeveloperPublicPoolBill
UDIDsyncDeveloper, DeveloperAppID, DeveloperDevicesID, IosDeveloperPublicPoolBill, UserInfo
from api.utils.app.iossignapi import ResignApp, AppDeveloperApiV2
from api.utils.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
@ -45,18 +45,14 @@ def check_org_file(user_obj, org_file):
return download_files_form_oss(storage_obj, org_file)
def resign_by_app_id(app_obj, need_download_profile=True, force=True):
user_obj = app_obj.user_id
info_list = []
if app_obj.issupersign and user_obj.supersign_active:
for developer_app_id_obj in DeveloperAppID.objects.filter(app_id=app_obj).all():
developer_obj = developer_app_id_obj.developerid
def resign_by_app_id_and_developer(app_id, developer_id, developer_app_id, need_download_profile=True, force=True):
app_obj = Apps.objects.filter(pk=app_id).first()
developer_obj = AppIOSDeveloperInfo.objects.filter(pk=developer_id).first()
if check_ipa_is_latest_sign(app_obj, developer_obj) and not force:
continue
return
add_new_bundles_prefix = f"check_or_add_new_bundles_{developer_obj.issuer_id}_{app_obj.app_id}"
if CleanErrorBundleIdSignDataState.get_state(add_new_bundles_prefix):
return False, '清理执行中,请等待'
developer_app_id = developer_app_id_obj.aid
d_time = time.time()
if need_download_profile:
with cache.lock("%s_%s_%s" % ('make_and_download_profile', developer_obj.issuer_id, app_obj.app_id),
@ -64,15 +60,13 @@ def resign_by_app_id(app_obj, need_download_profile=True, force=True):
IosUtils.modify_capability(developer_obj, app_obj, developer_app_id)
status, download_profile_result = IosUtils.make_and_download_profile(app_obj,
developer_obj,
add_new_bundles_prefix,
developer_app_id_obj)
add_new_bundles_prefix)
else:
status = True
with cache.lock("%s_%s_%s" % ('run_sign', app_obj.app_id, developer_obj.issuer_id), timeout=60 * 10):
if status:
status, result = IosUtils.run_sign(user_obj, app_obj, developer_obj, d_time, [])
info_list.append({'developer_id': developer_obj.issuer_id, 'result': (status, result)})
return info_list
status, result = IosUtils.run_sign(app_obj.user_id, app_obj, developer_obj, d_time, [])
return status, {'developer_id': developer_obj.issuer_id, 'result': (status, result)}
def check_app_sign_limit(app_obj):
@ -249,51 +243,54 @@ def call_function_try_attempts(try_attempts=3, sleep_time=2, failed_callback=Non
return decorator
def get_developer_user_by_app_udid(user_obj, udid):
use_device_obj = APPSuperSignUsedInfo.objects.filter(udid__udid__udid=udid,
user_id=user_obj, developerid__is_actived=True,
developerid__certid__isnull=False).first()
# 只要账户下面存在udid,就可以使用该苹果开发者账户,避免多个开发者账户下面出现同一个udid
if use_device_obj:
developer_obj = use_device_obj.developerid
else:
developer_udid_obj = UDIDsyncDeveloper.objects.filter(udid=udid,
def get_developer_user_by_app_udid(user_objs, udid, app_obj):
developer_udid_obj_list = UDIDsyncDeveloper.objects.filter(developerid__user_id__in=user_objs,
developerid__is_actived=True,
developerid__certid__isnull=False).first()
if developer_udid_obj and developer_udid_obj.developerid.user_id.pk == user_obj.pk:
developer_obj = developer_udid_obj.developerid
else:
for developer_obj in AppIOSDeveloperInfo.objects.filter(user_id=user_obj, is_actived=True,
developerid__certid__isnull=False).values(
'developerid').distinct()
# 根据udid和应用查找该用户开发者账户【主要可能是开发者未激活】
developer_obj = AppIOSDeveloperInfo.objects.filter(
pk__in=developer_udid_obj_list.filter(udid=udid, developerid__apptodeveloper__app_id=app_obj)).first()
if developer_obj:
logger.info(f'udid:{udid} app_obj:{app_obj} return')
return developer_obj, True
# 根据udid查找开发者账户
developer_obj = AppIOSDeveloperInfo.objects.filter(pk__in=developer_udid_obj_list.filter(udid=udid)).first()
if developer_obj:
logger.info(f'udid:{udid} only and return')
return developer_obj, True
# 根据app查找开发者账户
for developer_obj in AppIOSDeveloperInfo.objects.filter(
pk__in=developer_udid_obj_list.filter(developerid__apptodeveloper__app_id=app_obj)):
if get_developer_udided(developer_obj)[1] + get_developer_can_used_from_public_sign(
developer_obj.user_id) < developer_obj.usable_number:
logger.info(f'app_obj:{app_obj} only and return')
return developer_obj, False
for developer_obj in AppIOSDeveloperInfo.objects.filter(user_id__in=user_objs, is_actived=True,
certid__isnull=False).order_by("created_time"):
if get_developer_udided(developer_obj)[1] + get_developer_can_used_from_public_sign(
user_obj) < developer_obj.usable_number:
developer_obj.user_id) < developer_obj.usable_number:
logger.info(f'get suitable developer and return')
return developer_obj, False
return None, None
return developer_obj, True
def get_developer_obj_by_others(user_obj, udid):
result, is_exist = get_developer_user_by_app_udid(user_obj, udid)
def get_developer_obj_by_others(user_obj, udid, app_obj):
result, is_exist = get_developer_user_by_app_udid([user_obj], udid, app_obj)
if result:
return result
receive_user_obj_list = IosDeveloperPublicPoolBill.objects.filter(to_user_id=user_obj).all()
for receive_user_obj in receive_user_obj_list:
result, is_exist = get_developer_user_by_app_udid(receive_user_obj.user_id, udid)
if result is None:
continue
else:
receive_user_id_list = IosDeveloperPublicPoolBill.objects.filter(to_user_id=user_obj).values('user_id').distinct()
result, is_exist = get_developer_user_by_app_udid(UserInfo.objects.filter(pk__in=receive_user_id_list), udid,
app_obj)
f_count = get_ios_developer_public_num(user_obj)
if not is_exist and f_count > 0:
logger.warning(f"user receive_user_obj {receive_user_obj.user_id} developer to sign")
return result
if is_exist:
if f_count > 0:
return result
if f_count == 0 and udid in [x.get('udid__udid__udid') for x in
APPSuperSignUsedInfo.objects.filter(user_id=user_obj).values(
'udid__udid__udid').all()]:
if (f_count == 0 and is_exist) or f_count > 0:
return result
return None
class IosUtils(object):
@ -307,7 +304,7 @@ class IosUtils(object):
self.get_developer_auth()
def get_developer_auth(self):
self.developer_obj = get_developer_obj_by_others(self.user_obj, self.udid)
self.developer_obj = get_developer_obj_by_others(self.user_obj, self.udid, self.app_obj)
if self.developer_obj:
self.auth = get_auth_form_developer(self.developer_obj)
else:
@ -659,7 +656,7 @@ class IosUtils(object):
with cache.lock(register_devices_prefix, timeout=60):
if CleanErrorBundleIdSignDataState.get_state(add_new_bundles_prefix):
return True, True # 程序错误,进行清理的时候,拦截多余的设备注册
if not get_developer_obj_by_others(self.user_obj, self.udid):
if not get_developer_obj_by_others(self.user_obj, self.udid, self.app_obj):
d_result['code'] = 1005
return False, d_result
status, did_udid_result = IosUtils.check_or_register_devices(self.app_obj, self.user_obj,

@ -9,7 +9,9 @@ import base64
import datetime
import logging
import os
import time
from collections import namedtuple
from functools import wraps
import jwt
import requests
@ -648,6 +650,33 @@ class Certificates(namedtuple("Certificates",
return filepath
def call_function_try_attempts(try_attempts=3, sleep_time=1):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
res = False, {}
start_time = time.time()
flag = False
for i in range(try_attempts):
try:
res = func(*args, **kwargs)
flag = True
break
except Exception as e:
logger.warning(
f'exec {func} failed. Failed:{e} {try_attempts} times in total. now {sleep_time} later try '
f'again...{i}')
time.sleep(sleep_time)
if not flag:
logger.error(f'exec {func} failed after the maximum number of attempts. Failed:{res}')
logger.info(f"exec {func} finished. time:{time.time() - start_time}")
return res
return wrapper
return decorator
class AppStoreConnectApi(DevicesAPI, BundleIDsAPI, BundleIDsCapabilityAPI, ProfilesAPI, CertificatesAPI):
BASE_URI = 'https://api.appstoreconnect.apple.com/v1'
JWT_AUD = 'appstoreconnect-v1'
@ -744,6 +773,7 @@ class AppStoreConnectApi(DevicesAPI, BundleIDsAPI, BundleIDsCapabilityAPI, Profi
def __bundle_ids_store(self, req, success_code=200):
return self.__base_format('bundleIds', req, success_code)
@call_function_try_attempts()
def get_all_devices(self):
req = self.list_devices()
return self.__device_store(req)
@ -760,10 +790,12 @@ class AppStoreConnectApi(DevicesAPI, BundleIDsAPI, BundleIDsCapabilityAPI, Profi
req = self.list_profiles()
return self.__profile_store(req)
@call_function_try_attempts()
def get_all_certificates(self):
req = self.list_certificate()
return self.__certificates_store(req)
@call_function_try_attempts()
def get_certificate_by_cid(self, certificate_id):
req = self.list_certificate_by_certificate_id(certificate_id)
return self.__certificates_store(req)
@ -776,6 +808,7 @@ class AppStoreConnectApi(DevicesAPI, BundleIDsAPI, BundleIDsCapabilityAPI, Profi
raise Exception('more than one Device obj')
return device_obj_list
@call_function_try_attempts()
def register_device(self, device_name, device_udid, platform="IOS"):
device_obj_list = BaseInfoObj.filter(self.get_all_devices(), {"udid": device_udid})
# 发现同一个开发者账户里面有两个一样的udid,奇了怪
@ -788,6 +821,7 @@ class AppStoreConnectApi(DevicesAPI, BundleIDsAPI, BundleIDsCapabilityAPI, Profi
req = super().register_device(device_name, device_udid, platform)
return self.__device_store(req, 201)
@call_function_try_attempts()
def enabled_device(self, device_id, device_name, udid):
if device_id and device_name:
req = super().enabled_device(device_id, device_name)
@ -799,6 +833,7 @@ class AppStoreConnectApi(DevicesAPI, BundleIDsAPI, BundleIDsCapabilityAPI, Profi
req = self.modify_registered_device(device_obj.id, device_obj.name, 'ENABLED')
return self.__device_store(req)
@call_function_try_attempts()
def disabled_device(self, device_id, device_name, udid):
if device_id and device_name:
req = super().disabled_device(device_id, device_name)
@ -819,6 +854,7 @@ class AppStoreConnectApi(DevicesAPI, BundleIDsAPI, BundleIDsCapabilityAPI, Profi
return True
return False
@call_function_try_attempts()
def enable_capability_by_s_type(self, bundle_id, s_type):
capability_list = get_capability(s_type)
if capability_list:
@ -830,6 +866,7 @@ class AppStoreConnectApi(DevicesAPI, BundleIDsAPI, BundleIDsCapabilityAPI, Profi
logger.warning(f"{bundle_id} enable_capability {capability} failed {req.content}")
return True
@call_function_try_attempts()
def disable_capability_by_s_type(self, bundle_id, s_type=len(capability_info) - 1):
capability_list = get_capability(s_type)
if capability_list:
@ -857,6 +894,7 @@ class AppStoreConnectApi(DevicesAPI, BundleIDsAPI, BundleIDsCapabilityAPI, Profi
return True
return False
@call_function_try_attempts()
def register_bundle_id(self, bundle_id_name, bundle_id_identifier, platform="IOS", seed_id=''):
identifier_obj = self.list_bundle_ids_by_identifier(bundle_id_identifier)
if isinstance(identifier_obj, BundleIds):
@ -866,6 +904,7 @@ class AppStoreConnectApi(DevicesAPI, BundleIDsAPI, BundleIDsCapabilityAPI, Profi
req = super().register_bundle_id(bundle_id_name, bundle_id_identifier, platform, seed_id)
return self.__bundle_ids_store(req, 201)
@call_function_try_attempts()
def register_bundle_id_enable_capability(self, bundle_id_name, bundle_id_identifier, s_type, platform="IOS",
seed_id=''):
bundle_ids = self.register_bundle_id(bundle_id_name, bundle_id_identifier, platform, seed_id)
@ -873,6 +912,7 @@ class AppStoreConnectApi(DevicesAPI, BundleIDsAPI, BundleIDsCapabilityAPI, Profi
if self.enable_capability_by_s_type(bundle_ids.id, s_type):
return bundle_ids
@call_function_try_attempts()
def delete_bundle_by_identifier(self, identifier_id, identifier_name):
if identifier_id:
req = self.delete_bundle_id_by_id(identifier_id)
@ -884,6 +924,7 @@ class AppStoreConnectApi(DevicesAPI, BundleIDsAPI, BundleIDsCapabilityAPI, Profi
if req.status_code == 204:
return True
@call_function_try_attempts()
def create_profile(self, profile_id, bundle_id, certificate_id, profile_name, device_id_list=None,
profile_type='IOS_APP_ADHOC'):
if device_id_list is None:
@ -906,6 +947,7 @@ class AppStoreConnectApi(DevicesAPI, BundleIDsAPI, BundleIDsCapabilityAPI, Profi
req = super().list_profile_by_profile_name(profile_name)
return self.__profile_store(req)
@call_function_try_attempts()
def delete_profile_by_id(self, profile_id, profile_name):
if profile_id:
req = super().delete_profile(profile_id)
@ -917,12 +959,14 @@ class AppStoreConnectApi(DevicesAPI, BundleIDsAPI, BundleIDsCapabilityAPI, Profi
if self.__do_success(req, 204):
return True
@call_function_try_attempts()
def create_certificate(self, csr_content, certificate_type='IOS_DISTRIBUTION'):
req = super().create_certificate(csr_content, certificate_type)
if req.status_code == 201:
return self.__certificates_store(req, 201)
raise KeyError(req.text)
@call_function_try_attempts()
def revoke_certificate(self, certificate_id):
req = super().revoke_certificate(certificate_id)
if req.status_code == 204:

@ -146,7 +146,8 @@ def get_user_public_sign_num(user_obj):
def get_user_public_used_sign_num(user_obj):
used_number = IosDeveloperPublicPoolBill.objects.filter(user_id=user_obj, action=0,
udid_sync_info__isnull=False).values('number',
udid_sync_info__isnull=False).exclude(
udid_sync_info__developerid__user_id=user_obj).values('number',
'udid_sync_info_id').annotate(
counts=Count('udid_sync_info_id')).aggregate(number=Sum('number'))
number = used_number.get("number", 0)

@ -207,16 +207,16 @@ class AppInfoView(APIView):
if new_bundle_id != app_obj.new_bundle_id:
do_sign_flag = 2
app_obj.new_bundle_id = new_bundle_id
if new_bundle_id == '':
if new_bundle_id != app_obj.new_bundle_id:
if new_bundle_id == '' or (app_obj.new_bundle_id != new_bundle_id):
if app_obj.bundle_id != app_obj.new_bundle_id:
do_sign_flag = 2
app_obj.new_bundle_id = None
app_obj.new_bundle_id = app_obj.bundle_id
if new_bundle_name and new_bundle_name != app_obj.name and len(new_bundle_name) > 0:
if new_bundle_name != app_obj.new_bundle_name:
do_sign_flag = 2
app_obj.new_bundle_name = new_bundle_name
if new_bundle_name == '':
if new_bundle_name == '' or (app_obj.new_bundle_name != new_bundle_name):
if app_obj.name != app_obj.new_bundle_name:
do_sign_flag = 2
app_obj.new_bundle_name = app_obj.name
@ -244,16 +244,13 @@ class AppInfoView(APIView):
if app_obj.issupersign:
c_task = None
if do_sign_flag == 1:
c_task = run_resign_task.apply_async((app_obj.app_id, True))
c_task = run_resign_task(app_obj.pk, True)
if do_sign_flag == 2:
c_task = run_resign_task.apply_async((app_obj.app_id, False))
c_task = run_resign_task(app_obj.pk, False)
if do_sign_flag == 3:
c_task = run_resign_task.apply_async((app_obj.app_id, False, False))
c_task = run_resign_task(app_obj.pk, False, False)
if c_task:
msg = c_task.get(propagate=False)
logger.info(f"app {app_obj} run_resign_task msg:{msg}")
if c_task.successful():
c_task.forget()
logger.info(f"app {app_obj} run_resign_task msg:{c_task}")
del_cache_response_by_short(app_obj.app_id)
except Exception as e:
logger.error(f"app_id:{app_id} update Exception:{e}")

@ -303,7 +303,6 @@ class DeveloperDeviceView(APIView):
super_sign_used_objs = super_sign_used_objs.filter(developerid__issuer_id=developer_id)
if udid:
super_sign_used_objs = super_sign_used_objs.filter(udid=udid)
page_obj = PageNumber()
app_page_serializer = page_obj.paginate_queryset(queryset=super_sign_used_objs.order_by('-id'),
request=request,

@ -128,12 +128,8 @@ class AppAnalyseView(APIView):
app_obj = Apps.objects.filter(bundle_id=data.get("bundleid"), user_id=request.user).first()
if app_obj:
if app_obj.issupersign and app_obj.user_id.supersign_active:
c_task = run_resign_task.apply_async((app_obj.app_id, False, False))
msg = c_task.get(propagate=False)
logger.info(f"app {app_obj} run_resign_task msg:{msg}")
if c_task.successful():
c_task.forget()
c_task = run_resign_task(app_obj.pk, False, False)
logger.info(f"app {app_obj} run_resign_task msg:{c_task}")
else:
storage.delete_file(app_tmp_filename)
storage.delete_file(png_tmp_filename)

Loading…
Cancel
Save