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)