优化超级签 获取开发者账户逻辑,增加微信删除必须输入密码限制

qrnn
youngS 3 years ago
parent 106ae636a2
commit 205505cb0e
  1. 12
      fir_client/src/components/user/FirSuperSignBase.vue
  2. 12
      fir_client/src/components/user/FirUserProfileInfo.vue
  3. 5
      fir_client/src/components/user/FirUserStorage.vue
  4. 49
      fir_ser/api/utils/app/iossignapi.py
  5. 110
      fir_ser/api/utils/app/supersignutils.py
  6. 2
      fir_ser/api/utils/apple/appleapiv3.py
  7. 13
      fir_ser/api/utils/modelutils.py
  8. 2
      fir_ser/api/views/supersign.py
  9. 17
      fir_ser/api/views/thirdlogin.py

@ -65,26 +65,26 @@
<el-input v-model="editdeveloperinfo.description"/>
</el-form-item>
<div style="">
<el-button v-if="isedit && editdeveloperinfo.is_actived && editdeveloperinfo.certid" size="small"
<el-button v-if="isedit && editdeveloperinfo.certid" size="small"
@click="exportcert">导出证书
</el-button>
<el-button v-if="isedit && editdeveloperinfo.is_actived && !editdeveloperinfo.certid" size="small"
<el-button v-if="isedit && !editdeveloperinfo.certid" size="small"
@click="importcertDeveloperVisible=true">导入p12证书
</el-button>
<el-button v-if="isedit && editdeveloperinfo.is_actived && editdeveloperinfo.certid" size="small"
<el-button v-if="isedit && editdeveloperinfo.certid" size="small"
type="danger"
@click="cleandevices">清理签名数据
</el-button>
<el-button v-if="isedit && editdeveloperinfo.is_actived" size="small" @click="syncdevices">同步设备信息
<el-button v-if="isedit && editdeveloperinfo.is_actived || editdeveloperinfo.certid" size="small" @click="syncdevices">同步设备信息
</el-button>
<el-tooltip content="发布证书只能创建两个,请谨慎操作">
<el-button v-if="isedit && editdeveloperinfo.is_actived && !editdeveloperinfo.certid"
<el-button v-if="isedit && !editdeveloperinfo.certid"
size="small"
@click="isocertcert">手动创建发布证书
</el-button>
</el-tooltip>
<el-tooltip content="清理发布证书,如果发布证书过期时间大于3天,将不会删除开发者发布证书,发布证书只能同时创建两个,请谨慎操作">
<el-button v-if="isedit && editdeveloperinfo.is_actived && editdeveloperinfo.certid"
<el-button v-if="isedit && editdeveloperinfo.certid"
size="small"
type="danger"
@click="isorenewcert">删除发布证书

@ -307,17 +307,19 @@ export default {
}
}, methods: {
delete_wx_u(wx_user_info) {
this.$confirm(`此操作将导致微信用户 “${wx_user_info.nickname}” 无法通过扫码登录, 是否继续删除?`, '提示', {
this.$prompt(`此操作将导致微信用户 “${wx_user_info.nickname}” 无法通过扫码登录, 是否继续删除?`, '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
inputPlaceholder: '该用户的登录密码',
inputValidator: this.validFun
}).then(({value}) => {
this.wxUtilsFun({
methods: 'DELETE',
methods: 'POST',
data: {
"size": this.pagination.pagesize,
"page": this.pagination.currentPage,
"openid": wx_user_info.openid,
"confirm_pwd": value
}
})
}).catch(() => {
@ -332,6 +334,8 @@ export default {
if (data.code === 1000) {
this.wx_user_list = data.data;
this.show_wx_visible = true
} else if (data.code === 1001) {
this.$message.error(data.msg)
} else {
this.$message.error("获取授权列表失败")
}

@ -407,10 +407,7 @@ export default {
},
validFun(val) {
if (val && val.length > 6) {
return true
}
return false
return val && val.length > 6;
},
clean_storage_data(act) {

@ -196,9 +196,17 @@ def make_pem(cer_content, pem_path):
def check_error_call_back(error):
logger.error(error)
msg = ''
if 'Cannot connect to proxy' in error or 'Read timed out' in error or 'Max retries exceeded with' in error:
logger.error('access apple api failed . change proxy ip again')
msg = "代理网络错误,请稍后重试或联系管理员处理"
if 'it may be encrypted with an unsupported algorithm' in error:
msg = "数据校验失败,请检查p8key内容是否正常"
if 'Authentication credentials are missing or invalid' in error:
msg = '认证失败,请检查开发者信息填写是否正确'
logger.error(f"{msg} {error}")
return msg if msg else error
class AppDeveloperApiV2(object):
@ -221,8 +229,7 @@ class AppDeveloperApiV2(object):
return True, result
except Exception as e:
logger.error(f"ios developer active Failed Exception:{e}")
check_error_call_back(str(e))
result['return_info'] = "%s" % e
result['return_info'] = check_error_call_back(str(e))
return False, result
def file_format_path_name(self, user_obj):
@ -250,8 +257,7 @@ class AppDeveloperApiV2(object):
return True, certificates
except Exception as e:
logger.error(f"ios developer create cert Failed Exception:{e}")
check_error_call_back(str(e))
result['return_info'] = "%s" % e
result['return_info'] = check_error_call_back(str(e))
return False, result
def get_cert_obj_by_cid(self):
@ -266,8 +272,7 @@ class AppDeveloperApiV2(object):
return False, result
except Exception as e:
logger.error(f"ios developer get cert {self.cert_id} Failed Exception:{e}")
check_error_call_back(str(e))
result['return_info'] = "%s" % e
result['return_info'] = check_error_call_back(str(e))
return False, result
def revoke_cert(self):
@ -286,8 +291,7 @@ class AppDeveloperApiV2(object):
return True, result
except Exception as e:
logger.error(f"ios developer cert {self.cert_id} revoke Failed Exception:{e}")
check_error_call_back(str(e))
result['return_info'] = "%s" % e
result['return_info'] = check_error_call_back(str(e))
return False, result
def auto_set_certid_by_p12(self, app_dev_pem):
@ -307,8 +311,7 @@ class AppDeveloperApiV2(object):
return False, result
except Exception as e:
logger.error(f"ios developer cert {app_dev_pem} auto get Failed Exception:{e}")
check_error_call_back(str(e))
result['return_info'] = "%s" % e
result['return_info'] = check_error_call_back(str(e))
return False, result
def del_profile(self, profile_id, profile_name):
@ -319,8 +322,7 @@ class AppDeveloperApiV2(object):
return True
except Exception as e:
logger.error(f"ios developer delete profile Failed Exception:{e}")
check_error_call_back(str(e))
result['return_info'] = "%s" % e
result['return_info'] = check_error_call_back(str(e))
return False, result
def set_device_status(self, status, device_id, device_name, device_udid, failed_call_prefix,
@ -337,8 +339,7 @@ class AppDeveloperApiV2(object):
return True, result
except Exception as e:
logger.error("ios developer set devices status Failed Exception:%s" % e)
check_error_call_back(str(e))
result['return_info'] = "%s" % e
result['return_info'] = check_error_call_back(str(e))
if device_err_callback and ("There are no current ios devices" in str(e) or "Device obj is None" in str(e)):
with CleanErrorBundleIdSignDataState(failed_call_prefix) as state:
if state:
@ -358,8 +359,7 @@ class AppDeveloperApiV2(object):
return True, devices_obj_list
except Exception as e:
logger.error("ios developer get device Failed Exception:%s" % e)
check_error_call_back(str(e))
result['return_info'] = "%s" % e
result['return_info'] = check_error_call_back(str(e))
return False, result
def del_app(self, identifier_id, bundle_id, app_id):
@ -371,8 +371,7 @@ class AppDeveloperApiV2(object):
except Exception as e:
logger.error("ios developer delete app Failed Exception:%s" % e)
check_error_call_back(str(e))
result['return_info'] = "%s" % e
result['return_info'] = check_error_call_back(str(e))
return False, result
def create_app(self, bundle_id, app_id, s_type, app_id_err_callback=None):
@ -393,8 +392,7 @@ class AppDeveloperApiV2(object):
except Exception as e:
logger.error("ios developer create app Failed Exception:%s" % e)
check_error_call_back(str(e))
result['return_info'] = "%s" % e
result['return_info'] = check_error_call_back(str(e))
if app_id_err_callback and "There is no App ID with ID" in str(e):
for call_fun in app_id_err_callback:
call_fun()
@ -407,8 +405,7 @@ class AppDeveloperApiV2(object):
return True, apple_obj.register_device(device_name, device_udid)
except Exception as e:
logger.error("ios developer register device Failed Exception:%s" % e)
check_error_call_back(str(e))
result['return_info'] = "%s" % e
result['return_info'] = check_error_call_back(str(e))
if device_err_callback and "There are no current ios devices" in str(e):
with CleanErrorBundleIdSignDataState(failed_call_prefix) as state:
@ -439,8 +436,7 @@ class AppDeveloperApiV2(object):
return True, result
except Exception as e:
logger.error(f"app_id {app_obj.app_id} ios developer make profile Failed Exception:{e}")
check_error_call_back(str(e))
result['return_info'] = "%s" % e
result['return_info'] = check_error_call_back(str(e))
if app_id_err_callback and "There is no App ID with ID" in str(e):
with CleanErrorBundleIdSignDataState(failed_call_prefix) as state:
if state:
@ -474,6 +470,5 @@ class AppDeveloperApiV2(object):
return True, result
except Exception as e:
logger.error("ios developer modify_capability Failed Exception:%s" % e)
check_error_call_back(str(e))
result['return_info'] = "%s" % e
result['return_info'] = check_error_call_back(str(e))
return False, result

@ -21,7 +21,7 @@ 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
from api.utils.modelutils import get_ios_developer_public_num, check_ipa_is_latest_sign, \
get_developer_can_used_from_public_sign
get_developer_can_used_from_public_sign, update_or_create_developer_udid_info
from api.utils.response import BaseResponse
from api.utils.serializer import BillAppInfoSerializer, BillDeveloperInfoSerializer
from api.utils.storage.caches import del_cache_response_by_short, send_msg_over_limit, check_app_permission, \
@ -278,7 +278,7 @@ def get_new_developer_by_app_obj(user_objs, app_obj, apple_to_app=False):
developer_obj_lists = obj_base_filter.filter(appledevelopertoappuse__app_id=app_obj)
else:
developer_obj_lists = obj_base_filter.exclude(appledevelopertoappuse__developerid__isnull=False)
developer_obj_lists = developer_obj_lists.distinct().order_by("created_time")
developer_obj_lists = developer_obj_lists.all().distinct().order_by("created_time")
for developer_obj in developer_obj_lists:
# 通过开发者数限制进行过滤
used_number = get_developer_udided(developer_obj)[2] + get_developer_can_used_from_public_sign(
@ -288,60 +288,97 @@ def get_new_developer_by_app_obj(user_objs, app_obj, apple_to_app=False):
apple_to_app_obj = AppleDeveloperToAppUse.objects.filter(app_id=app_obj,
developerid=developer_obj).first()
if apple_to_app_obj:
if used_number < apple_to_app_obj.usable_number:
# 通过配置的专属分配数量进行过滤
app_used_number = DeveloperDevicesID.objects.filter(developerid=developer_obj,
app_id=app_obj).distinct().count()
if app_used_number < apple_to_app_obj.usable_number:
can_used_developer_pk_list.append(developer_obj.pk)
else:
can_used_developer_pk_list.append(developer_obj.pk)
return can_used_developer_pk_list
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,
def get_developer_by_pk_list(developer_pk_list, f_key):
developer_obj_dict = AppIOSDeveloperInfo.objects.filter(pk__in=developer_pk_list,
is_actived=True,
certid__isnull=False).values(
f_key, 'pk').annotate(
count=Count('pk')).order_by('created_time').order_by('count').first()
if developer_obj_dict:
developer_obj = AppIOSDeveloperInfo.objects.filter(pk=developer_obj_dict.get('pk')).first()
logger.info(f'get {f_key} suitable developer {developer_obj} and return')
return developer_obj
def get_developer_user_by_app_udid(user_objs, udid, app_obj, private_first=True):
"""
:param user_objs: [user_obj]
:param udid: udid
:param app_obj: app_obj
:param private_first: 专属应用优先使用专属开发者而不是公共开发者
:return: (developer_obj, is_exist_devices)
"""
developer_udid_queryset = UDIDsyncDeveloper.objects.filter(developerid__user_id__in=user_objs,
developerid__is_actived=True,
developerid__certid__isnull=False).values(
'developerid').distinct()
'developerid').all().distinct()
# 根据udid和应用查找该用户开发者账户【主要可能是开发者未激活】
developer_obj = AppIOSDeveloperInfo.objects.filter(
pk__in=developer_udid_obj_list.filter(udid=udid, developerid__apptodeveloper__app_id=app_obj)).last()
if developer_obj:
logger.info(f'udid:{udid} app_obj:{app_obj} return')
return developer_obj, True
developer_pk_list = developer_udid_queryset.filter(udid=udid, developerid__apptodeveloper__app_id=app_obj)
app_search_flag = True
# 联合udid和应用查询不到数据,那么,仅根据udid查找开发者账户
if not developer_pk_list:
app_search_flag = False
developer_pk_list = developer_udid_queryset.filter(udid=udid)
# 根据udid查找开发者账户
developer_obj = AppIOSDeveloperInfo.objects.filter(pk__in=developer_udid_obj_list.filter(udid=udid)).last()
if developer_pk_list:
developer_obj = get_developer_by_pk_list(developer_pk_list, 'developerappid')
if developer_obj:
logger.info(f'udid:{udid} only and return')
if app_search_flag:
logger.info(f'udid:{udid} and app_obj:{app_obj} exist and return. developer_obj: {developer_obj}')
else:
logger.info(f'udid:{udid} exist and return. app_obj:{app_obj} developer_obj: {developer_obj}')
return developer_obj, True
else:
logger.info(f"udid:{udid} is a new device. app_obj:{app_obj} will find a suitable developer and register it")
# 新设备查找策略
# 根据app查找开发者账户
exist_app_developer_pk_list = []
for developer_obj in AppIOSDeveloperInfo.objects.filter(
pk__in=developer_udid_obj_list.filter(developerid__apptodeveloper__app_id=app_obj)):
developer_pk_list = developer_udid_queryset.filter(developerid__apptodeveloper__app_id=app_obj)
if developer_pk_list:
for developer_obj in AppIOSDeveloperInfo.objects.filter(pk__in=developer_pk_list):
if get_developer_udided(developer_obj)[2] + 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')
exist_app_developer_pk_list.append(developer_obj.pk)
# return developer_obj, False
# 查询状态正常的专属开发者信息,判断是否为专属应用
apple_to_app = AppleDeveloperToAppUse.objects.filter(app_id=app_obj, developerid__is_actived=True,
developerid__certid__isnull=False).first()
# 存在专属开发者账户,但是也同时存在已经安装的设备,优先选择已经安装设备的开发者账户?是or否
# 是:使应用趋向于一个开发者,为后期更新提供方便
# 否:优先使用专属开发者进行签名
if not private_first and apple_to_app and exist_app_developer_pk_list:
return AppIOSDeveloperInfo.objects.filter(pk=exist_app_developer_pk_list[0]).first(), False
can_used_developer_pk_list = get_new_developer_by_app_obj(user_objs, app_obj, apple_to_app)
# 存在指定开发者账户,但是获取可用的开发者账户为空,那么开始匹配全部开发者
if not can_used_developer_pk_list and apple_to_app:
logger.info(f"udid:{udid} app_obj:{app_obj} private developer is null. start find all developer")
can_used_developer_pk_list = get_new_developer_by_app_obj(user_objs, app_obj)
if can_used_developer_pk_list and exist_app_developer_pk_list:
can_used_developer_pk_list = list(set(can_used_developer_pk_list) & set(exist_app_developer_pk_list))
logger.info(f"udid:{udid} app_obj:{app_obj} find private and can use developer {can_used_developer_pk_list}")
# 查询开发者策略 按照最小注册设备数进行查找,这样可以分散,进而使应用趋向于一个开发者,为后期更新提供方便
if can_used_developer_pk_list:
developer_obj_dict = AppIOSDeveloperInfo.objects.filter(pk__in=can_used_developer_pk_list).values(
'udidsyncdeveloper', 'pk').annotate(
count=Count('pk')).order_by('created_time').order_by('count').first()
if developer_obj_dict:
developer_obj = AppIOSDeveloperInfo.objects.filter(pk=developer_obj_dict.get('pk')).first()
logger.info(f'get suitable developer {developer_obj} and return')
developer_obj = get_developer_by_pk_list(can_used_developer_pk_list, 'udidsyncdeveloper')
if developer_obj:
logger.info(f"udid:{udid} is a new device. app_obj:{app_obj} find {developer_obj} and return")
return developer_obj, False
return None, None
@ -517,12 +554,7 @@ class IosUtils(object):
if app_udid_obj and app_udid_obj.is_download:
sign_flag = False
if app_udid_obj.is_signed:
# release_obj = AppReleaseInfo.objects.filter(app_id=self.app_obj, is_master=True).first()
if check_ipa_is_latest_sign(self.app_obj, self.developer_obj):
#
# for apptodev_obj in APPToDeveloper.objects.filter(app_id=self.app_obj).all():
# if release_obj.release_id == apptodev_obj.release_file:
msg = "udid %s exists app_id %s" % (self.udid, self.app_obj)
d_result['msg'] = msg
logger.info(d_result)
@ -581,15 +613,7 @@ class IosUtils(object):
if not status:
return status, device_obj
device = {
"serial": device_obj.id,
"product": device_obj.name,
"udid": device_obj.udid,
"version": device_obj.model,
"status": True if device_obj.status == 'ENABLED' else False
}
sync_device_obj, _ = UDIDsyncDeveloper.objects.update_or_create(developerid=developer_obj,
udid=device_obj.udid, defaults=device)
sync_device_obj, _ = update_or_create_developer_udid_info(device_obj, developer_obj)
# 更新设备状态
# 1. UDIDsyncDeveloper 库,通过udid 更新或创建设备信息
@ -1040,15 +1064,7 @@ class IosUtils(object):
will_del_disabled_udid_list = list(set(udid_developer_list) - set(udid_enabled_result_list))
for device_obj in result:
device = {
"serial": device_obj.id,
"product": device_obj.name,
"udid": device_obj.udid,
"version": device_obj.model,
"status": True if device_obj.status == 'ENABLED' else False
}
obj, create = UDIDsyncDeveloper.objects.update_or_create(developerid=developer_obj,
udid=device_obj.udid, defaults=device)
obj, create = update_or_create_developer_udid_info(device_obj, developer_obj)
if not create:
DeveloperDevicesID.objects.filter(udid=obj, developerid=developer_obj).update(
**{'did': device_obj.id})

@ -705,7 +705,7 @@ def call_function_try_attempts(try_attempts=5, sleep_time=3):
f'again...{i}')
res = str(e)
if 'Authentication credentials are missing or invalid' in str(e):
res = '认证失败,请检查开发者信息填写是否正确'
raise Exception(res)
time.sleep(sleep_time)
logger.info(f"exec {func} finished. time:{time.time() - start_time}")
if not flag:

@ -12,7 +12,7 @@ from urllib.parse import urljoin
from django.db.models import Count, Sum, Q
from api.models import AppReleaseInfo, UserDomainInfo, DomainCnameInfo, UserAdDisplayInfo, RemoteClientInfo, \
AppIOSDeveloperInfo, IosDeveloperPublicPoolBill, APPToDeveloper, UserInfo
AppIOSDeveloperInfo, IosDeveloperPublicPoolBill, APPToDeveloper, UserInfo, UDIDsyncDeveloper
from api.utils.baseutils import get_server_domain_from_request, get_user_default_domain_name, get_real_ip_address, \
get_origin_domain_name, is_valid_phone
@ -203,3 +203,14 @@ def get_user_obj_from_epu(user_id):
else:
user_obj = UserInfo.objects.filter(Q(email=user_id) | Q(uid=user_id)).first()
return user_obj
def update_or_create_developer_udid_info(device_obj, developer_obj):
device = {
"serial": device_obj.id,
"product": device_obj.name,
"udid": device_obj.udid,
"version": device_obj.model,
"status": True if device_obj.status == 'ENABLED' else False
}
return UDIDsyncDeveloper.objects.update_or_create(developerid=developer_obj, udid=device_obj.udid, defaults=device)

@ -110,7 +110,7 @@ class DeveloperView(APIView):
IosUtils.get_device_from_developer(developer_obj)
else:
res.code = 1008
res.msg = result.get("err_info")
res.msg = result.get("return_info")
return Response(res.dict)
elif act == "renewcert":
if developer_obj.certid:

@ -183,7 +183,6 @@ class ValidWxChatToken(APIView):
WxTemplateMsg().query_bind_info_failed_msg(to_user, wx_user_info.get('nickname'),
"查询登录绑定", content)
elif rec_msg.Eventkey == 'unbind':
if wx_user_obj:
content = f'解绑用户 {wx_user_obj.user_id.first_name} 成功'
@ -234,12 +233,8 @@ class ThirdWxAccount(APIView):
def get(self, request):
res = BaseResponse()
if get_login_type().get('third', '').get('wxp'):
# wx_open_id = request.query_params.get("openid", None)
wx_obj_lists = ThirdWeChatUserInfo.objects.filter(user_id=request.user)
# if wx_open_id:
# wx_obj_lists = wx_obj_lists.filter(openid=wx_open_id)
page_obj = PageNumber()
info_serializer = page_obj.paginate_queryset(queryset=wx_obj_lists.order_by("-subscribe_time"),
request=request,
@ -247,11 +242,17 @@ class ThirdWxAccount(APIView):
wx_user_info = ThirdWxSerializer(info_serializer, many=True, )
res.data = wx_user_info.data
res.count = wx_obj_lists.count()
return Response(res.dict)
def delete(self, request):
openid = request.query_params.get("openid")
def post(self, request):
data = request.data
openid = data.get("openid")
if get_login_type().get('third', '').get('wxp') and openid:
if request.user.check_password(data.get('confirm_pwd', '')):
ThirdWeChatUserInfo.objects.filter(user_id=request.user, openid=openid).delete()
else:
res = BaseResponse()
res.code = 1001
res.msg = "密码有误,请检查"
return Response(res.dict)
return self.get(request)

Loading…
Cancel
Save