增加应用签名限额

pull/6/head
youngS 4 years ago
parent 348c6a16f5
commit 5a85eb20d6
  1. 23
      fir_client/src/components/FirAppInfossupersign.vue
  2. 130
      fir_client/src/components/FirDownload.vue
  3. 117
      fir_client/src/components/ShortDownload.vue
  4. 4
      fir_client/src/main.js
  5. 23
      fir_ser/api/migrations/0021_auto_20210308_1951.py
  6. 1
      fir_ser/api/models.py
  7. 12
      fir_ser/api/utils/app/iossignapi.py
  8. 119
      fir_ser/api/utils/app/supersignutils.py
  9. 52
      fir_ser/api/utils/apple/appleapiv3.py
  10. 13
      fir_ser/api/views/apps.py
  11. 22
      fir_ser/api/views/receiveudids.py
  12. 2
      fir_ser/api/views/uploads.py

@ -25,6 +25,22 @@
</el-form-item>
<el-form-item label-width="200px" label="签名限额"
v-if="currentapp.type === 1 && $store.state.userinfo.supersign_active ">
<el-tooltip content="本应用签名使用额度,超过该额度,新设备将无法安装本应用" placement="top">
<el-input-number v-model="currentapp.supersign_limit_number" :disabled="supersign_disable"
:placeholder="defualt_dtitle" :min="0"
style="width: 60%;margin-right: 10px" label="签名限额"></el-input-number>
</el-tooltip>
<el-button @click="saveappinfo({supersign_limit_number:currentapp.supersign_limit_number})"
:disabled="supersign_disable"
>保存
</el-button>
</el-form-item>
<el-form-item label-width="200px" label="签名类型"
v-if="currentapp.type === 1 && $store.state.userinfo.supersign_active ">
@ -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,

@ -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
})
})
}
},

@ -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
})
})
}
},

@ -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;

@ -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'),
),
]

@ -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)

@ -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:

@ -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):

@ -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=''):

@ -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)

@ -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))

@ -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)

Loading…
Cancel
Save