From 5a85eb20d67aac8c42d346677b915b6a17c31518 Mon Sep 17 00:00:00 2001 From: youngS Date: Tue, 9 Mar 2021 15:21:31 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=BA=94=E7=94=A8=E7=AD=BE?= =?UTF-8?q?=E5=90=8D=E9=99=90=E9=A2=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/FirAppInfossupersign.vue | 23 ++++ fir_client/src/components/FirDownload.vue | 130 ++++++++++-------- fir_client/src/components/ShortDownload.vue | 117 +++++++++------- fir_client/src/main.js | 4 +- .../api/migrations/0021_auto_20210308_1951.py | 23 ++++ fir_ser/api/models.py | 1 + fir_ser/api/utils/app/iossignapi.py | 12 +- fir_ser/api/utils/app/supersignutils.py | 119 +++++++++++----- fir_ser/api/utils/apple/appleapiv3.py | 52 ++++--- fir_ser/api/views/apps.py | 13 +- fir_ser/api/views/receiveudids.py | 22 ++- fir_ser/api/views/uploads.py | 2 +- 12 files changed, 341 insertions(+), 177 deletions(-) create mode 100644 fir_ser/api/migrations/0021_auto_20210308_1951.py diff --git a/fir_client/src/components/FirAppInfossupersign.vue b/fir_client/src/components/FirAppInfossupersign.vue index 1d8ed89..28ad1a8 100644 --- a/fir_client/src/components/FirAppInfossupersign.vue +++ b/fir_client/src/components/FirAppInfossupersign.vue @@ -25,6 +25,22 @@ + + + + + + + + 保存 + + + @@ -87,6 +103,12 @@ this.currentapp.count = 0; }, saveappinfo(data) { + const loading = this.$loading({ + lock: true, + text: '执行中,请耐心等待...', + spinner: 'el-icon-loading', + background: 'rgba(0, 0, 0, 0.7)' + }); apputils(data => { if (data.code === 1000) { this.$message.success('数据更新成功'); @@ -94,6 +116,7 @@ this.$message.error('操作失败,' + data.msg); this.$store.dispatch('doucurrentapp', this.orgcurrentapp); } + loading.close(); }, { "methods": "PUT", "app_id": this.currentapp.app_id, diff --git a/fir_client/src/components/FirDownload.vue b/fir_client/src/components/FirDownload.vue index 94e721a..51860c9 100644 --- a/fir_client/src/components/FirDownload.vue +++ b/fir_client/src/components/FirDownload.vue @@ -229,75 +229,93 @@ gomobileaction() { window.location.href = this.mobileprovision; }, + check_msg(callback) { + if (this.$route.query.msg && this.$route.query.udid) { + this.wrong = true; + this.msg = this.$route.query.msg; + this.$message({ + message: this.msg, + type: 'error', + duration: 0 + }); + } else ( + callback() + ) + }, + download() { if (this.currentappinfo.app_id) { - this.isdownload = true; - getdownloadurl(res => { - if (res.code === 1000) { - if (res.data.download_url === "") { - window.location.href = this.full_url.split("?")[0]; - return - } - if (this.currentappinfo.type === 1) { - if (this.currentappinfo.issupersign) { - if (this.$route.query.udid && this.udid === this.$route.query.udid) { - if (this.agent !== '') { - let download_url = res.data.download_url; - this.downloadurl = "itms-services://?action=download-manifest&url=" + encodeURIComponent(download_url); + // eslint-disable-next-line no-unused-vars + this.check_msg(_ => { + this.isdownload = true; + getdownloadurl(res => { + if (res.code === 1000) { + if (res.data.download_url === "") { + window.location.href = this.full_url.split("?")[0]; + return + } + if (this.currentappinfo.type === 1) { + if (this.currentappinfo.issupersign) { + if (this.$route.query.udid && this.udid === this.$route.query.udid) { + if (this.agent !== '') { + let download_url = res.data.download_url; + this.downloadurl = "itms-services://?action=download-manifest&url=" + encodeURIComponent(download_url); + // eslint-disable-next-line no-unused-vars + this.timmer = setTimeout(data => { + this.gomobile = false; + }, 5000); + } + } else { + if (this.agent !== '') { + this.downloadurl = res.data.download_url; + window.location.href = this.downloadurl; + if (res.data.extra_url !== "") { + // eslint-disable-next-line no-unused-vars + this.timmer = setTimeout(data => { + window.location.href = res.data.extra_url; + }, 3000); + } + + return; + } + } + } else { + let download_url = res.data.download_url; + this.downloadurl = "itms-services://?action=download-manifest&url=" + encodeURIComponent(download_url); + if (res.data.extra_url !== "") { + this.mobileprovision = res.data.extra_url; // eslint-disable-next-line no-unused-vars this.timmer = setTimeout(data => { this.gomobile = false; }, 5000); } - } else { - if (this.agent !== '') { - this.downloadurl = res.data.download_url; - window.location.href = this.downloadurl; - if (res.data.extra_url !== "") { - // eslint-disable-next-line no-unused-vars - this.timmer = setTimeout(data => { - window.location.href = res.data.extra_url; - }, 3000); - } - - return; - } } } else { - let download_url = res.data.download_url; - this.downloadurl = "itms-services://?action=download-manifest&url=" + encodeURIComponent(download_url); - if (res.data.extra_url !== "") { - this.mobileprovision = res.data.extra_url; - // eslint-disable-next-line no-unused-vars - this.timmer = setTimeout(data => { - this.gomobile = false; - }, 5000); + if (this.agent !== '') { + this.downloadurl = res.data.download_url; } } + + window.location.href = this.downloadurl; } else { - if (this.agent !== '') { - this.downloadurl = res.data.download_url; - } + this.isdownload = false; + this.password = ''; + this.$message({ + message: "密码错误,或者下载链接失效", + type: 'error', + }); + window.location.reload(); } - - window.location.href = this.downloadurl; - } else { - this.isdownload = false; - this.password = ''; - this.$message({ - message: "密码错误,或者下载链接失效", - type: 'error', - }); - } - }, { - 'data': { - 'token': this.mcurrentappinfo.download_token, - 'short': this.currentappinfo.short, - 'release_id': this.mcurrentappinfo.release_id, - 'password': this.password, - 'udid': this.udid, - }, - 'app_id': this.currentappinfo.app_id + }, { + 'data': { + 'token': this.mcurrentappinfo.download_token, + 'short': this.currentappinfo.short, + 'release_id': this.mcurrentappinfo.release_id, + 'password': this.password, + 'udid': this.udid, + }, + 'app_id': this.currentappinfo.app_id + }) }) } }, diff --git a/fir_client/src/components/ShortDownload.vue b/fir_client/src/components/ShortDownload.vue index 98309fa..9a5db39 100644 --- a/fir_client/src/components/ShortDownload.vue +++ b/fir_client/src/components/ShortDownload.vue @@ -232,71 +232,84 @@ gomobileaction() { window.location.href = this.mobileprovision; }, + check_msg(callback) { + if (this.$route.query.msg && this.$route.query.udid) { + this.wrong = true; + this.msg = this.$route.query.msg; + alert(this.msg) + } else ( + callback() + ) + }, download() { if (this.currentappinfo.app_id) { - this.isdownload = true; - getdownloadurl(res => { - if (res.code === 1000) { - if (res.data.download_url === "") { - window.location.href = this.full_url.split("?")[0]; - return - } - if (this.currentappinfo.type === 1) { - if (this.currentappinfo.issupersign) { - if (this.$route.query.udid && this.udid === this.$route.query.udid) { - if (this.agent !== '') { - let download_url = res.data.download_url; - this.downloadurl = "itms-services://?action=download-manifest&url=" + encodeURIComponent(download_url); + // eslint-disable-next-line no-unused-vars + this.check_msg(_ => { + this.isdownload = true; + getdownloadurl(res => { + if (res.code === 1000) { + if (res.data.download_url === "") { + window.location.href = this.full_url.split("?")[0]; + return + } + if (this.currentappinfo.type === 1) { + if (this.currentappinfo.issupersign) { + if (this.$route.query.udid && this.udid === this.$route.query.udid) { + if (this.agent !== '') { + let download_url = res.data.download_url; + this.downloadurl = "itms-services://?action=download-manifest&url=" + encodeURIComponent(download_url); + // eslint-disable-next-line no-unused-vars + this.timmer = setTimeout(data => { + this.gomobile = false; + }, 5000); + } + } else { + if (this.agent !== '') { + this.downloadurl = res.data.download_url; + window.location.href = this.downloadurl; + if (res.data.extra_url !== "") { + // eslint-disable-next-line no-unused-vars + this.timmer = setTimeout(data => { + window.location.href = res.data.extra_url; + }, 3000); + } + + return; + } + } + } else { + let download_url = res.data.download_url; + this.downloadurl = "itms-services://?action=download-manifest&url=" + encodeURIComponent(download_url); + if (res.data.extra_url !== "") { + this.mobileprovision = res.data.extra_url; // eslint-disable-next-line no-unused-vars this.timmer = setTimeout(data => { this.gomobile = false; }, 5000); } - } else { - if (this.agent !== '') { - this.downloadurl = res.data.download_url; - window.location.href = this.downloadurl; - if (res.data.extra_url !== "") { - // eslint-disable-next-line no-unused-vars - this.timmer = setTimeout(data => { - window.location.href = res.data.extra_url; - }, 3000); - } - - return; - } } } else { - let download_url = res.data.download_url; - this.downloadurl = "itms-services://?action=download-manifest&url=" + encodeURIComponent(download_url); - if (res.data.extra_url !== "") { - this.mobileprovision = res.data.extra_url; - // eslint-disable-next-line no-unused-vars - this.timmer = setTimeout(data => { - this.gomobile = false; - }, 5000); + if (this.agent !== '') { + this.downloadurl = res.data.download_url; } } + + window.location.href = this.downloadurl; } else { - if (this.agent !== '') { - this.downloadurl = res.data.download_url; - } + this.isdownload = false; + alert("密码错误,或者下载链接失效"); + window.location.reload(); } - - window.location.href = this.downloadurl; - } else { - this.isdownload = false; - alert("密码错误,或者下载链接失效") - } - }, { - 'data': { - 'token': this.mcurrentappinfo.download_token, - 'short': this.currentappinfo.short, - 'release_id': this.mcurrentappinfo.release_id, - 'password': this.password, - 'udid': this.udid, - }, - 'app_id': this.currentappinfo.app_id + }, { + 'data': { + 'token': this.mcurrentappinfo.download_token, + 'short': this.currentappinfo.short, + 'release_id': this.mcurrentappinfo.release_id, + 'password': this.password, + 'udid': this.udid, + }, + 'app_id': this.currentappinfo.app_id + }) }) } }, diff --git a/fir_client/src/main.js b/fir_client/src/main.js index 0fff95c..9b47125 100644 --- a/fir_client/src/main.js +++ b/fir_client/src/main.js @@ -94,7 +94,8 @@ import { TimelineItem, Card, Notification, - Footer + Footer, + InputNumber } from "element-ui"; Vue.use(Progress); @@ -143,6 +144,7 @@ Vue.use(Tag); Vue.use(Tooltip); Vue.use(Switch); Vue.use(Footer); +Vue.use(InputNumber); Vue.prototype.$message = Message; Vue.prototype.$notify = Notification; Vue.prototype.$loading = Loading.service; diff --git a/fir_ser/api/migrations/0021_auto_20210308_1951.py b/fir_ser/api/migrations/0021_auto_20210308_1951.py new file mode 100644 index 0000000..c554999 --- /dev/null +++ b/fir_ser/api/migrations/0021_auto_20210308_1951.py @@ -0,0 +1,23 @@ +# Generated by Django 3.0.3 on 2021-03-08 19:51 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ('api', '0020_auto_20210308_1453'), + ] + + operations = [ + migrations.AddField( + model_name='apps', + name='supersign_limit_number', + field=models.IntegerField(default=0, verbose_name='签名使用限额'), + ), + migrations.AlterField( + model_name='apps', + name='new_bundle_id', + field=models.CharField(blank=True, help_text='用于超级签某些因素下需要修改包名', max_length=64, null=True, + verbose_name='new_bundle_id'), + ), + ] diff --git a/fir_ser/api/models.py b/fir_ser/api/models.py index ac2fb7d..3386a87 100644 --- a/fir_ser/api/models.py +++ b/fir_ser/api/models.py @@ -117,6 +117,7 @@ class Apps(models.Model): supersign_type = models.SmallIntegerField(choices=supersign_type_choices, default=0, verbose_name="签名类型") new_bundle_id = models.CharField(max_length=64, blank=True, null=True, verbose_name="new_bundle_id", help_text="用于超级签某些因素下需要修改包名") + supersign_limit_number = models.IntegerField(verbose_name="签名使用限额", default=0) wxredirect = models.BigIntegerField(verbose_name="微信内第三方链接自动跳转", default=True) wxeasytype = models.BigIntegerField(verbose_name="微信内简易模式,避免微信封停", default=True) domain_name = models.CharField(verbose_name="专属访问域名", blank=True, null=True, max_length=64) diff --git a/fir_ser/api/utils/app/iossignapi.py b/fir_ser/api/utils/app/iossignapi.py index e1cc49c..d85cfea 100644 --- a/fir_ser/api/utils/app/iossignapi.py +++ b/fir_ser/api/utils/app/iossignapi.py @@ -129,8 +129,10 @@ class ResignApp(object): info_plist_properties = {} properties = "" for k, v in info_plist_properties.items(): - properties += " %s=%s " % (k, v) - self.cmd = self.cmd + " -i '%s' -p '%s' -o '%s' '%s'" % (properties, new_profile, new_ipa, org_ipa) + properties += "%s=%s," % (k, v) + if properties: + properties = " -i '%s' " % properties[0:-1] + self.cmd = self.cmd + " %s -p '%s' -o '%s' '%s'" % (properties, new_profile, new_ipa, org_ipa) return exec_shell(self.cmd) @@ -213,7 +215,7 @@ class AppDeveloperApiV2(object): def get_profile(self, app_obj, udid_info, provisionName, auth, developer_app_id, device_id_list): result = {} - bundle_id = app_obj.bundleId + bundle_id = app_obj.bundle_id app_id = app_obj.app_id try: apple_obj = AppStoreConnectApi(self.issuer_id, self.private_key_id, self.p8key) @@ -319,14 +321,14 @@ class AppDeveloperApiV2(object): return False, result def modify_capability(self, app_obj, developer_app_id): - bundle_id = app_obj.bundleId + bundle_id = app_obj.bundle_id app_id = app_obj.app_id result = {} try: apple_obj = AppStoreConnectApi(self.issuer_id, self.private_key_id, self.p8key) if developer_app_id: if app_obj.supersign_type == 0: - result['code'] = apple_obj.disable_all_capability(developer_app_id) + result['code'] = apple_obj.disable_push_vpn_capability(developer_app_id) else: result['code'] = apple_obj.enable_push_vpn_capability(developer_app_id) else: diff --git a/fir_ser/api/utils/app/supersignutils.py b/fir_ser/api/utils/app/supersignutils.py index f1b8925..e6dc909 100644 --- a/fir_ser/api/utils/app/supersignutils.py +++ b/fir_ser/api/utils/app/supersignutils.py @@ -25,13 +25,23 @@ def resign_by_app_obj(app_obj, need_download_profile=True): for dappid_obj in DeveloperAppID.objects.filter(app_id=app_obj).all(): developer_obj = dappid_obj.developerid developer_app_id = dappid_obj.aid + d_time = time.time() if need_download_profile: IosUtils.modify_capability(developer_obj, app_obj, developer_app_id) download_flag, result = IosUtils.exec_download_profile(app_obj, developer_obj, 2) else: download_flag = True - IosUtils.run_sign(user_obj, app_obj, developer_obj, download_flag, None, - resign=True) + IosUtils.run_sign(user_obj, app_obj, developer_obj, download_flag, None, d_time, {}, True) + + +def check_app_sign_limit(app_obj): + used_num = APPSuperSignUsedInfo.objects.filter(app_id=app_obj).all().count() + limit_num = app_obj.supersign_limit_number + if limit_num <= 0: + flag = True + else: + flag = used_num <= limit_num + return flag, used_num def udid_bytes_to_dict(xml_stream): @@ -291,6 +301,8 @@ class IosUtils(object): developer_app_id = None auth = get_auth_form_developer(developer_obj) while sign_try_attempts > 0: + logger.info("exec_download_profile appid:%s developer:%s sign_try_attempts:%s" % ( + app_obj, developer_obj, sign_try_attempts)) device_id_list = DeveloperDevicesID.objects.filter(app_id=app_obj, developerid=developer_obj).values_list('did') developer_app_id = None @@ -332,8 +344,11 @@ class IosUtils(object): resign_app_obj = ResignApp(my_local_key, app_dev_pem) org_file = os.path.join(MEDIA_ROOT, release_obj.release_id + ".ipa") new_file = os.path.join(MEDIA_ROOT, random_file_name + ".ipa") + properties_info = {} + if app_obj.new_bundle_id: + properties_info = {'CFBundleIdentifier': app_obj.new_bundle_id} status, result = resign_app_obj.sign(get_profile_full_path(developer_obj, app_obj), org_file, new_file, - app_obj.new_bundle_id) + properties_info) if status: logger.info("%s %s %s sign_ipa success" % (user_obj, developer_obj, app_obj)) return True @@ -342,6 +357,20 @@ class IosUtils(object): "%s %s %s sign_ipa failed ERROR:%s" % (user_obj, developer_obj, app_obj, result.get("err_info"))) return False + @staticmethod + def update_sign_file_name(app_obj, developer_obj, release_obj, random_file_name): + apptodev_obj = APPToDeveloper.objects.filter(developerid=developer_obj, app_id=app_obj).first() + if apptodev_obj: + storage = LocalStorage("localhost", False) + storage.del_file(apptodev_obj.binary_file + ".ipa") + apptodev_obj.binary_file = random_file_name + apptodev_obj.release_file = release_obj.release_id + apptodev_obj.save() + + else: + APPToDeveloper.objects.create(developerid=developer_obj, app_id=app_obj, + binary_file=random_file_name, release_file=release_obj.release_id) + def update_sign_data(self, random_file_name, release_obj, result): newdata = { "is_signed": True, @@ -385,48 +414,51 @@ class IosUtils(object): DeveloperDevicesID.objects.create(did=result["did"], udid=app_udid_obj, developerid=self.developer_obj, app_id=self.app_obj) - # 创建 - apptodev_obj = APPToDeveloper.objects.filter(developerid=self.developer_obj, app_id=self.app_obj).first() - if apptodev_obj: - storage = LocalStorage("localhost", False) - storage.del_file(apptodev_obj.binary_file + ".ipa") - apptodev_obj.binary_file = random_file_name - apptodev_obj.release_file = release_obj.release_id - apptodev_obj.save() - - else: - APPToDeveloper.objects.create(developerid=self.developer_obj, app_id=self.app_obj, - binary_file=random_file_name, release_file=release_obj.release_id) - - # if not developer_app_id and result.get("aid", None): - # DeveloperAppID.objects.create(aid=result["aid"], developerid=self.developer_obj, app_id=self.app_obj) + # 更新新签名的ipa包 + IosUtils.update_sign_file_name(self.app_obj, self.developer_obj, release_obj, random_file_name) @staticmethod - def run_sign(user_obj, app_obj, developer_obj, download_flag, obj, resign=False): - result = {} + def run_sign(user_obj, app_obj, developer_obj, download_flag, obj, d_time, result, resign=False): + d_result = {'code': 0, 'msg': 'success'} start_time = time.time() - d_time1 = time.time() if download_flag: - logger.info("app_id %s download profile success. time:%s" % (app_obj, d_time1 - start_time)) + logger.info("app_id %s download profile success. time:%s" % (app_obj, start_time - d_time)) random_file_name = make_from_user_uuid(user_obj) - release_obj = AppReleaseInfo.objects.filter(app_id=app_obj, is_master=True).first() if IosUtils.exec_sign(user_obj, app_obj, developer_obj, random_file_name, release_obj): s_time1 = time.time() - logger.info("app_id %s exec sign ipa success. time:%s" % (app_obj, s_time1 - d_time1)) - if not resign: + logger.info("app_id %s exec sign ipa success. time:%s" % (app_obj, s_time1 - start_time)) + if resign: + IosUtils.update_sign_file_name(app_obj, developer_obj, release_obj, random_file_name) + else: obj.update_sign_data(random_file_name, release_obj, result) else: - logger.error("app_id %s download profile failed. %s time:%s" % (app_obj, result, d_time1 - start_time)) - return False - logger.info( - "app_id %s developer %s sign end... time:%s" % (app_obj, developer_obj, time.time() - start_time)) - return True + msg = "app_id %s download profile failed. %s time:%s" % (app_obj, result, time.time() - start_time) + d_result['code'] = 1002 + d_result['msg'] = msg + logger.error(d_result) + return False, d_result + msg = "app_id %s developer %s sign end... time:%s" % (app_obj, developer_obj, time.time() - start_time) + logger.info(msg) + d_result['msg'] = msg + return True, d_result def sign(self, sign_try_attempts=3, resign=False): + d_result = {'code': 0, 'msg': 'success'} + state, used_num = check_app_sign_limit(self.app_obj) + if not state: + d_result['code'] = 1003 + d_result['msg'] = "app_id %s used over limit.now %s limit: %s" % ( + self.app_obj, used_num, self.app_obj.supersign_limit_number) + logger.error(d_result) + return False, d_result + if not self.developer_obj: - logger.error("udid %s app %s not exists apple developer" % (self.udid_info.get('udid'), self.app_obj)) - return + msg = "udid %s app %s not exists apple developer" % (self.udid_info.get('udid'), self.app_obj) + d_result['code'] = 1001 + d_result['msg'] = msg + logger.error(d_result) + return False, d_result if not resign: app_udid_obj = AppUDID.objects.filter(app_id=self.app_obj, udid=self.udid_info.get('udid')).first() if app_udid_obj and app_udid_obj.is_signed: @@ -434,23 +466,36 @@ class IosUtils(object): if apptodev_obj: release_obj = AppReleaseInfo.objects.filter(app_id=self.app_obj, is_master=True).first() if release_obj.release_id == apptodev_obj.release_file: - logger.info("udid %s exists app_id %s" % (self.udid_info.get('udid'), self.app_obj)) - return + msg = "udid %s exists app_id %s" % (self.udid_info.get('udid'), self.app_obj) + d_result['msg'] = msg + logger.info(d_result) + return True, d_result logger.info("udid %s not exists app_id %s ,need sign" % (self.udid_info.get('udid'), self.app_obj)) else: logger.info("resign app_id %s ,need resign" % self.app_obj) call_flag = True download_flag = False + count = 1 + result = {} + start_time = time.time() while call_flag: + logger.info( + "call_loop download_profile appid:%s developer:%s count:%s" % (self.app_obj, self.developer_obj, count)) if self.developer_obj: download_flag, result = IosUtils.exec_download_profile(self.app_obj, self.developer_obj, sign_try_attempts) - if not download_flag: + if download_flag: + call_flag = False + else: self.get_developer_auth() else: call_flag = False - - IosUtils.run_sign(self.user_obj, self.app_obj, self.developer_obj, download_flag, self, resign=False) + count += 1 + if download_flag: + AppUDID.objects.update_or_create(app_id=self.app_obj, udid=self.udid_info.get('udid'), + defaults=self.udid_info) + return IosUtils.run_sign(self.user_obj, self.app_obj, self.developer_obj, download_flag, self, start_time, + result) @staticmethod def disable_udid(udid_obj, app_id): diff --git a/fir_ser/api/utils/apple/appleapiv3.py b/fir_ser/api/utils/apple/appleapiv3.py index 7212534..35fc12e 100644 --- a/fir_ser/api/utils/apple/appleapiv3.py +++ b/fir_ser/api/utils/apple/appleapiv3.py @@ -10,13 +10,21 @@ import os import datetime import requests import jwt +import logging from collections import namedtuple +logger = logging.getLogger(__file__) + # https://developer.apple.com/documentation/appstoreconnectapi/creating_api_keys_for_app_store_connect_api # https://appstoreconnect.apple.com/access/api 去申请秘钥 # +def request_format_log(req): + logger.info("url:%s header:%s code:%s body:%s" % (req.url, req.headers, req.status_code, req.content)) + return req + + class DevicesAPI(object): # https://developer.apple.com/documentation/appstoreconnectapi/devices def __init__(self, base_uri, jwt_headers): @@ -40,7 +48,7 @@ class DevicesAPI(object): if query_parameters: for k, v in query_parameters.items(): params[k] = v - return requests.get(self.devices_url, params=params, headers=self.headers) + return request_format_log(requests.get(self.devices_url, params=params, headers=self.headers)) def list_enabled_devices(self): return self.list_devices({"filter[status]": "ENABLED"}) @@ -73,7 +81,7 @@ class DevicesAPI(object): } } } - return requests.post(self.devices_url, json=json, headers=self.headers) + return request_format_log(requests.post(self.devices_url, json=json, headers=self.headers)) def read_device_information(self, device_id): """ @@ -88,7 +96,7 @@ class DevicesAPI(object): params = { "fields[devices]": "addedDate, deviceClass, model, name, platform, status, udid", } - return requests.get(base_url, params=params, headers=self.headers) + return request_format_log(requests.get(base_url, params=params, headers=self.headers)) def enabled_device(self, device_id, device_name): return self.modify_registered_device(device_id, device_name, 'ENABLED') @@ -119,7 +127,7 @@ class DevicesAPI(object): } } } - return requests.patch(base_url, json=json, headers=self.headers) + return request_format_log(requests.patch(base_url, json=json, headers=self.headers)) class BundleIDsAPI(object): @@ -151,7 +159,7 @@ class BundleIDsAPI(object): } } } - return requests.post(self.bundle_ids_url, json=json, headers=self.headers) + return request_format_log(requests.post(self.bundle_ids_url, json=json, headers=self.headers)) def delete_bundle_id_by_id(self, bundle_id): """ @@ -165,7 +173,7 @@ class BundleIDsAPI(object): """ base_url = '%s/%s' % (self.bundle_ids_url, bundle_id) json = {} - return requests.delete(base_url, json=json, headers=self.headers) + return request_format_log(requests.delete(base_url, json=json, headers=self.headers)) def list_bundle_ids(self, query_parameters=None): """ @@ -183,7 +191,7 @@ class BundleIDsAPI(object): if query_parameters: for k, v in query_parameters.items(): params[k] = v - return requests.get(self.bundle_ids_url, params=params, headers=self.headers) + return request_format_log(requests.get(self.bundle_ids_url, params=params, headers=self.headers)) def list_bundle_id_by_identifier(self, identifier): return self.list_bundle_ids({"filter[identifier]": identifier}) @@ -212,7 +220,7 @@ class BundleIDsAPI(object): } } } - return requests.patch(base_url, json=json, headers=self.headers) + return request_format_log(requests.patch(base_url, json=json, headers=self.headers)) class BundleIDsCapabilityAPI(object): @@ -221,7 +229,7 @@ class BundleIDsCapabilityAPI(object): self.headers = jwt_headers self.bundle_ids_capability_url = '%s/bundleIdCapabilities' % base_uri - def disable_capability(self, bundle_id): + def disable_capability(self, bundle_id, capability_type): """ :param bundle_id: :return: @@ -231,9 +239,9 @@ class BundleIDsCapabilityAPI(object): 404 ErrorResponse Not Found Resource not found. Content-Type: application/json 409 ErrorResponse Conflict The provided resource data is not valid. Content-Type: application/json """ - base_url = '%s/%s' % (self.bundle_ids_capability_url, bundle_id) + base_url = '%s/%s_%s' % (self.bundle_ids_capability_url, bundle_id, capability_type) json = {} - return requests.delete(base_url, json=json, headers=self.headers) + return request_format_log(requests.delete(base_url, json=json, headers=self.headers)) def enable_capability(self, bundle_id, capability_type): """ @@ -262,7 +270,7 @@ class BundleIDsCapabilityAPI(object): } } } - return requests.post(self.bundle_ids_capability_url, json=json, headers=self.headers) + return request_format_log(requests.post(self.bundle_ids_capability_url, json=json, headers=self.headers)) class ProfilesAPI(object): @@ -314,7 +322,7 @@ class ProfilesAPI(object): } } } - return requests.post(self.profiles_url, json=json, headers=self.headers) + return request_format_log(requests.post(self.profiles_url, json=json, headers=self.headers)) def delete_profile(self, profile_id): """ @@ -328,7 +336,7 @@ class ProfilesAPI(object): """ base_url = '%s/%s' % (self.profiles_url, profile_id) json = {} - return requests.delete(base_url, json=json, headers=self.headers) + return request_format_log(requests.delete(base_url, json=json, headers=self.headers)) def download_profile(self, profile_id): # n=base64.b64decode(profileContent) @@ -353,7 +361,7 @@ class ProfilesAPI(object): if query_parameters: for k, v in query_parameters.items(): params[k] = v - return requests.get(self.profiles_url, params=params, headers=self.headers) + return request_format_log(requests.get(self.profiles_url, params=params, headers=self.headers)) def list_profile_by_profile_id(self, profile_id): return self.list_profiles({"filter[id]": profile_id, "include": ""}) @@ -388,7 +396,7 @@ class CertificatesAPI(object): } } } - return requests.post(self.certificates_url, json=json, headers=self.headers) + return request_format_log(requests.post(self.certificates_url, json=json, headers=self.headers)) def download_certificate(self, certificate_id): # req.json()['data'][0]['attributes']['certificateContent'] @@ -413,7 +421,7 @@ class CertificatesAPI(object): if query_parameters: for k, v in query_parameters.items(): params[k] = v - return requests.get(self.certificates_url, params=params, headers=self.headers) + return request_format_log(requests.get(self.certificates_url, params=params, headers=self.headers)) def list_certificate_by_certificate_id(self, certificate_id): return self.list_certificate({"filter[id]": certificate_id, }) @@ -430,7 +438,7 @@ class CertificatesAPI(object): """ base_url = '%s/%s' % (self.certificates_url, certificate_id) json = {} - return requests.delete(base_url, json=json, headers=self.headers) + return request_format_log(requests.delete(base_url, json=json, headers=self.headers)) class BaseInfoObj(object): @@ -740,11 +748,13 @@ class AppStoreConnectApi(DevicesAPI, BundleIDsAPI, BundleIDsCapabilityAPI, Profi return True return False - def disable_all_capability(self, bundle_id): + def disable_push_vpn_capability(self, bundle_id): # 'PUSH_NOTIFICATIONS', # PERSONAL_VPN - req = super().disable_capability(bundle_id) + req = super().disable_capability(bundle_id, 'PUSH_NOTIFICATIONS') if self.__do_success(req, 204): - return True + req = super().disable_capability(bundle_id, 'PERSONAL_VPN') + if self.__do_success(req, 204): + return True return False def register_bundle_id(self, bundle_id_name, bundle_id_identifier, platform="IOS", seed_id=''): diff --git a/fir_ser/api/views/apps.py b/fir_ser/api/views/apps.py index f87979d..157bf77 100644 --- a/fir_ser/api/views/apps.py +++ b/fir_ser/api/views/apps.py @@ -218,12 +218,15 @@ class AppInfoView(APIView): return Response(res.dict) else: try: + do_sign_flag = 0 apps_obj = Apps.objects.filter(user_id=request.user, app_id=app_id).first() logger.info("app_id:%s update old data:%s" % (app_id, apps_obj.__dict__)) apps_obj.description = data.get("description", apps_obj.description) apps_obj.short = data.get("short", apps_obj.short) apps_obj.name = data.get("name", apps_obj.name) apps_obj.password = data.get("password", apps_obj.password) + apps_obj.supersign_limit_number = data.get("supersign_limit_number", + apps_obj.supersign_limit_number) apps_obj.isshow = data.get("isshow", apps_obj.isshow) domain_name = data.get("domain_name", None) if domain_name: @@ -245,11 +248,17 @@ class AppInfoView(APIView): if apps_obj.issupersign: if apps_obj.supersign_type in [x[0] for x in list(apps_obj.supersign_type_choices)]: + if apps_obj.supersign_type != data.get("supersign_type", apps_obj.supersign_type): + do_sign_flag = 1 apps_obj.supersign_type = data.get("supersign_type", apps_obj.supersign_type) new_bundle_id = data.get("new_bundle_id", None) if new_bundle_id and new_bundle_id != apps_obj.bundle_id and len(new_bundle_id) > 3: + if new_bundle_id != apps_obj.new_bundle_id: + do_sign_flag = 2 apps_obj.new_bundle_id = new_bundle_id if new_bundle_id == '': + if new_bundle_id != apps_obj.new_bundle_id: + do_sign_flag = 2 apps_obj.new_bundle_id = None apps_obj.wxredirect = data.get("wxredirect", apps_obj.wxredirect) @@ -271,9 +280,9 @@ class AppInfoView(APIView): logger.info("app_id:%s update new data:%s" % (app_id, apps_obj.__dict__)) apps_obj.save() if apps_obj.issupersign: - if apps_obj.supersign_type != data.get("supersign_type", apps_obj.supersign_type): + if do_sign_flag == 1: resign_by_app_obj(apps_obj) - if apps_obj.new_bundle_id != data.get("new_bundle_id", apps_obj.new_bundle_id): + if do_sign_flag == 2: resign_by_app_obj(apps_obj, need_download_profile=False) del_cache_response_by_short(apps_obj.app_id) diff --git a/fir_ser/api/views/receiveudids.py b/fir_ser/api/views/receiveudids.py index 7b32020..586ae0b 100644 --- a/fir_ser/api/views/receiveudids.py +++ b/fir_ser/api/views/receiveudids.py @@ -20,13 +20,15 @@ class IosUDIDView(View): format_udid_info = udid_bytes_to_dict(stream_f) logger.info("short %s get new udid %s" % (short, format_udid_info)) server_domain = get_redirect_server_domain(request) + msg = {} + status = True try: app_info = Apps.objects.filter(short=short).first() if app_info: if app_info.issupersign and app_info.user_id.supersign_active: ios_obj = IosUtils(format_udid_info, app_info.user_id, app_info) - ios_obj.sign() + status, msg = ios_obj.sign() else: return HttpResponsePermanentRedirect( "%s/%s" % (server_domain, short)) @@ -35,4 +37,20 @@ class IosUDIDView(View): "%s/%s" % (server_domain, short)) except Exception as e: logger.error("short %s receive udid Exception:%s" % (short, e)) - return HttpResponsePermanentRedirect("%s/%s?udid=%s" % (server_domain, short, format_udid_info.get("udid"))) + + if not status: + code = msg.get("code") + if code == 0: + msg = "" + elif code == 1001: + msg = "账户余额不足" + elif code == 1002: + msg = "维护中" + elif code == 1003: + msg = "应用余额不足" + else: + msg = "内部错误,请联系管理员" + else: + msg = "" + return HttpResponsePermanentRedirect( + "%s/%s?udid=%s&msg=%s" % (server_domain, short, format_udid_info.get("udid"), msg)) diff --git a/fir_ser/api/views/uploads.py b/fir_ser/api/views/uploads.py index 623b656..a502d46 100644 --- a/fir_ser/api/views/uploads.py +++ b/fir_ser/api/views/uploads.py @@ -121,7 +121,7 @@ class AppAnalyseView(APIView): app_info = Apps.objects.filter(bundle_id=data.get("bundleid")).first() if app_info: if app_info.issupersign and app_info.user_id.supersign_active: - resign_by_app_obj(app_info) + resign_by_app_obj(app_info, need_download_profile=False) else: storage.delete_file(app_tmp_filename)