xsign 模块

xsign
nineven 3 years ago
parent 8ce3b14475
commit f00135a6a4
  1. 4
      fir_client/src/components/apps/FirAppInfossupersign.vue
  2. 27
      fir_client/src/restful/download.js
  3. 33
      fir_client/src/restful/index.js
  4. 9
      fir_ser/api/utils/serializer.py
  5. 20
      fir_ser/api/views/download.py
  6. 2
      fir_ser/api/views/uploads.py
  7. 51
      fir_ser/common/base/baseutils.py
  8. 1
      fir_ser/common/core/singals.py
  9. 4
      fir_ser/common/core/sysconfig.py
  10. 7
      fir_ser/common/libs/storage/localApi.py
  11. 28
      fir_ser/common/utils/caches.py
  12. 8
      fir_ser/fir_ser/urls.py
  13. 52
      fir_ser/xsign/singals/downloadapp.py
  14. 51
      fir_ser/xsign/utils/utils.py
  15. 5
      fir_ser/xsign/views/download.py

@ -179,7 +179,7 @@ export default {
"data": data "data": data
}); });
}, },
getappinfo(){ getappinfo() {
appSignInfo(data => { appSignInfo(data => {
if (data.code === 1000) { if (data.code === 1000) {
for (let name of Object.keys(data.data)) { for (let name of Object.keys(data.data)) {
@ -244,7 +244,7 @@ export default {
}, },
appinit() { appinit() {
this.currentapp = this.$store.state.currentapp; this.currentapp = this.$store.state.currentapp;
if(this.currentapp.app_id){ if (this.currentapp.app_id) {
this.getappinfo(); this.getappinfo();
} }
this.set_default_flag(); this.set_default_flag();

@ -113,17 +113,6 @@ export function getdownloadurl(callBack, params) {
); );
} }
/**获取签名任务状态 */
export function gettask(callBack, params) {
getData(
'GET',
USERSEVER + '/task/' + params.short,
params.data,
data => {
callBack(data);
},
);
}
/**应用举报 */ /**应用举报 */
export function appReport(callBack, params) { export function appReport(callBack, params) {
@ -202,3 +191,19 @@ export function geetest(self, uid, params, callback) {
"data": {user_id: uid} "data": {user_id: uid}
}); });
} }
/** 超级签名************************************************相关api */
/**获取签名任务状态 */
let SIGNSEVER = DOMAIN + '/api/v1/fir/xsign';
export function gettask(callBack, params) {
getData(
'GET',
SIGNSEVER + '/task/' + params.short,
params.data,
data => {
callBack(data);
},
);
}

@ -589,21 +589,6 @@ export function domainFun(callBack, params, load = true) {
); );
} }
/**获取签名任务状态 */
export function gettask(callBack, params, load = true) {
getData(
'GET',
USERSEVER + '/task/' + params.short,
params.data,
data => {
callBack(data);
},
load,
true,
true
);
}
/**微信用户绑定 */ /**微信用户绑定 */
export function wxutils(callBack, params, load = true) { export function wxutils(callBack, params, load = true) {
@ -681,7 +666,7 @@ export function appReport(callBack, params, load = true) {
); );
} }
// 超级签名相关api /** 超级签名************************************************相关api */
let SIGNSEVER = DOMAIN + '/api/v1/fir/xsign'; let SIGNSEVER = DOMAIN + '/api/v1/fir/xsign';
@ -852,3 +837,19 @@ export function developercert(callBack, params, load = true) {
true true
); );
} }
/**获取签名任务状态 */
export function gettask(callBack, params, load = true) {
getData(
'GET',
SIGNSEVER + '/task/' + params.short,
params.data,
data => {
callBack(data);
},
load,
true,
true
);
}

@ -111,12 +111,13 @@ class AppsSerializer(serializers.ModelSerializer):
def get_preview_url(self, obj): def get_preview_url(self, obj):
return get_app_download_uri(None, obj.user_id, obj) return get_app_download_uri(None, obj.user_id, obj)
# private_developer_number = serializers.SerializerMethodField() private_developer_number = serializers.IntegerField(default=0)
count = serializers.IntegerField(default=0)
# #
# def get_private_developer_number(self, obj): # def get_private_developer_number(self, obj):
# return models.AppleDeveloperToAppUse.objects.filter(app_id=obj).count() # return models.AppleDeveloperToAppUse.objects.filter(app_id=obj).count()
# #
# private_developer_used_number = serializers.SerializerMethodField() private_developer_used_number = serializers.IntegerField(default=0)
# #
# def get_private_developer_used_number(self, obj): # def get_private_developer_used_number(self, obj):
# return models.DeveloperDevicesID.objects.filter(app_id=obj, # return models.DeveloperDevicesID.objects.filter(app_id=obj,
@ -132,12 +133,12 @@ class AppsSerializer(serializers.ModelSerializer):
def get_sign_type_choice(self, obj): def get_sign_type_choice(self, obj):
return get_choices_dict(obj.supersign_type_choices) return get_choices_dict(obj.supersign_type_choices)
# supersign_used_number = serializers.SerializerMethodField() supersign_used_number = serializers.IntegerField(default=0)
# #
# def get_supersign_used_number(self, obj): # def get_supersign_used_number(self, obj):
# return models.APPSuperSignUsedInfo.objects.filter(app_id=obj).all().count() # return models.APPSuperSignUsedInfo.objects.filter(app_id=obj).all().count()
# #
# developer_used_count = serializers.SerializerMethodField() developer_used_count = serializers.IntegerField(default=0)
# #
# def get_developer_used_count(self, obj): # def get_developer_used_count(self, obj):
# return models.DeveloperAppID.objects.filter(app_id=obj).all().count() # return models.DeveloperAppID.objects.filter(app_id=obj).all().count()

@ -16,9 +16,9 @@ from api.utils.modelutils import get_filename_form_file, check_app_domain_name_a
ad_random_weight, get_app_download_uri ad_random_weight, get_app_download_uri
from api.utils.response import BaseResponse from api.utils.response import BaseResponse
from api.utils.serializer import AppsShortSerializer, AppAdInfoSerializer from api.utils.serializer import AppsShortSerializer, AppAdInfoSerializer
from common.base.baseutils import get_origin_domain_name, format_get_uri from common.base.baseutils import get_origin_domain_name, format_get_uri, make_random_uuid, make_resigned
from common.core.decorators import cache_response # 本来使用的是 drf-extensions==0.7.0 但是还未支持该版本Django from common.core.decorators import cache_response # 本来使用的是 drf-extensions==0.7.0 但是还未支持该版本Django
from common.core.response import mobileprovision_file_response from common.core.response import mobileprovision_file_response, file_response, ApiResponse
from common.core.sysconfig import Config from common.core.sysconfig import Config
from common.core.throttle import VisitShortThrottle, InstallShortThrottle, InstallThrottle1, InstallThrottle2 from common.core.throttle import VisitShortThrottle, InstallShortThrottle, InstallThrottle1, InstallThrottle2
from common.utils.caches import check_app_permission, get_app_download_url from common.utils.caches import check_app_permission, get_app_download_url
@ -50,7 +50,21 @@ class DownloadView(APIView):
flag = verify_token(down_token, filename) flag = verify_token(down_token, filename)
if flag: if flag:
if f_type == 'dmobileprovision': # 企业签名安装信任跳转 if f_type == 'plist':
release_id = filename.split('.')[0]
release_obj = AppReleaseInfo.objects.filter(release_id=release_id).first()
if release_obj:
app_obj = release_obj.app_id
storage = Storage(app_obj.user_id)
bundle_id = app_obj.bundle_id
app_version = release_obj.app_version
name = app_obj.name
ios_plist_bytes = make_resigned(storage.get_download_url(filename.split('.')[0] + ".ipa"),
storage.get_download_url(release_obj.icon_url), bundle_id,
app_version, name)
return file_response(ios_plist_bytes, make_random_uuid(), "application/x-plist")
return ApiResponse(code=1004, msg="plist release_id error")
elif f_type == 'dmobileprovision': # 企业签名安装信任跳转
release_obj = AppReleaseInfo.objects.filter(release_id=filename.split('.')[0]).first() release_obj = AppReleaseInfo.objects.filter(release_id=filename.split('.')[0]).first()
if release_obj: if release_obj:
file_path = Config.DEFAULT_MOBILEPROVISION.get("enterprise").get('path') file_path = Config.DEFAULT_MOBILEPROVISION.get("enterprise").get('path')

@ -138,7 +138,7 @@ class AppAnalyseView(APIView):
storage.rename_file(app_tmp_filename, app_new_filename) storage.rename_file(app_tmp_filename, app_new_filename)
storage.rename_file(png_tmp_filename, png_new_filename) storage.rename_file(png_tmp_filename, png_new_filename)
app_obj = Apps.objects.filter(bundle_id=data.get("bundleid"), user_id=request.user, type=4).first() app_obj = Apps.objects.filter(bundle_id=data.get("bundleid"), user_id=request.user, type=1).first()
if app_obj: if app_obj:
run_resign_task_signal.send(sender=None, app_pk=app_obj.pk) run_resign_task_signal.send(sender=None, app_pk=app_obj.pk)
else: else:

@ -324,3 +324,54 @@ def get_choices_name_from_key(choices, key):
if choice[0] == key: if choice[0] == key:
return choice[1] return choice[1]
return '' return ''
def make_resigned(bin_url, img_url, bundle_id, app_version, name):
ios_plist_tem = """<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0"><dict>
<key>items</key>
<array>
<dict>
<key>assets</key>
<array>
<dict>
<key>kind</key>
<string>software-package</string>
<key>url</key>
<string><![CDATA[{bin_url}]]></string>
</dict>
<dict>
<key>kind</key>
<string>display-image</string>
<key>needs-shine</key>
<integer>0</integer>
<key>url</key>
<string><![CDATA[{img_url}]]></string>
</dict>
<dict>
<key>kind</key>
<string>full-size-image</string>
<key>needs-shine</key>
<true/>
<key>url</key>
<string><![CDATA[{img_url}]]></string>
</dict>
</array>
<key>metadata</key>
<dict>
<key>bundle-identifier</key>
<string>{bundle_id}</string>
<key>bundle-version</key>
<string><![CDATA[{app_version}]]></string>
<key>kind</key>
<string>software</string>
<key>title</key>
<string><![CDATA[{name}]]></string>
</dict>
</dict>
</array>
</dict>
</plist>""".format(bin_url=bin_url, img_url=img_url, bundle_id=bundle_id, app_version=app_version, name=name)
logger.info(
f"make_resigned bin_url {bin_url} ,img_url {img_url}, bundle_id {bundle_id}, app_version {app_version}, name {name}")
return ios_plist_tem

@ -27,6 +27,7 @@ def run_resign_task_callback(sender, **kwargs):
if app_obj.change_auto_sign: if app_obj.change_auto_sign:
c_task = run_resign_task(app_obj.pk, False, False) c_task = run_resign_task(app_obj.pk, False, False)
logger.info(f"app {app_obj} run_resign_task end msg:{c_task}") logger.info(f"app {app_obj} run_resign_task end msg:{c_task}")
return 'success'
""" """

@ -323,6 +323,10 @@ class AppleDeveloperConfCache(ConfigCacheBase):
def DEVELOPER_DISABLED_STATUS(self): def DEVELOPER_DISABLED_STATUS(self):
return super().get_value('DEVELOPER_DISABLED_STATUS', APPLEDEVELOPERCONF.DEVELOPER_DISABLED_STATUS) return super().get_value('DEVELOPER_DISABLED_STATUS', APPLEDEVELOPERCONF.DEVELOPER_DISABLED_STATUS)
@property
def DEVELOPER_UID_KEY(self):
return super().get_value('DEVELOPER_UID_KEY', APPLEDEVELOPERCONF.DEVELOPER_UID_KEY)
class ConfigCache(BaseConfCache, IpaConfCache, AuthConfCache, EmailMsgCache, UserDownloadTimesCache, GeeTestConfCache, class ConfigCache(BaseConfCache, IpaConfCache, AuthConfCache, EmailMsgCache, UserDownloadTimesCache, GeeTestConfCache,
PayConfCache, ThirdPartConfCache, AppleDeveloperConfCache): PayConfCache, ThirdPartConfCache, AppleDeveloperConfCache):

@ -31,8 +31,11 @@ class LocalStorage(object):
uri = 'https://' if self.is_https else 'http://' uri = 'https://' if self.is_https else 'http://'
return f"{uri}{self.domain_name}" return f"{uri}{self.domain_name}"
def get_download_url(self, name, expires=600, force_new=False): def get_download_url(self, name, expires=600, force_new=False, is_xsign=False):
download_url = '/'.join([self.get_base_url(), 'download', name]) d_dir = 'download'
if name.endswith('.mobileconifg') or is_xsign:
d_dir = 'xdownload'
download_url = '/'.join([self.get_base_url(), d_dir, name])
if self.download_auth_type == 1: if self.download_auth_type == 1:
download_url = f"{download_url}?{settings.DATA_DOWNLOAD_KEY}={make_token(name, expires, force_new=force_new)}" download_url = f"{download_url}?{settings.DATA_DOWNLOAD_KEY}={make_token(name, expires, force_new=force_new)}"
elif self.download_auth_type == 2: elif self.download_auth_type == 2:

@ -12,7 +12,7 @@ from django.core.cache import cache
from django.db.models import F from django.db.models import F
from django.utils import timezone from django.utils import timezone
from api.models import Apps, UserInfo, AppReleaseInfo, UserCertificationInfo, Order from api.models import Apps, UserInfo, UserCertificationInfo, Order
from api.utils.modelutils import get_app_d_count_by_app_id, get_app_domain_name, get_user_domain_name, \ from api.utils.modelutils import get_app_d_count_by_app_id, get_app_domain_name, get_user_domain_name, \
add_remote_info_from_request add_remote_info_from_request
from common.base.baseutils import check_app_password, get_order_num, get_real_ip_address from common.base.baseutils import check_app_password, get_order_num, get_real_ip_address
@ -24,6 +24,7 @@ from common.cache.storage import AppDownloadTodayTimesCache, AppDownloadTimesCac
from common.core.sysconfig import Config from common.core.sysconfig import Config
from common.utils.storage import Storage, LocalStorage from common.utils.storage import Storage, LocalStorage
from fir_ser.settings import CACHE_KEY_TEMPLATE, SYNC_CACHE_TO_DATABASE from fir_ser.settings import CACHE_KEY_TEMPLATE, SYNC_CACHE_TO_DATABASE
from xsign.singals.downloadapp import xsign_app_download_url_signal
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -44,28 +45,9 @@ def get_download_url_by_cache(app_obj, filename, limit, isdownload=True, key='',
if app_obj.get('issupersign', None): if app_obj.get('issupersign', None):
download_url_type = 'mobileconifg' download_url_type = 'mobileconifg'
else: else:
appudid_obj = AppUDID.objects.filter(app_id_id=app_obj.get("pk"), udid__udid=udid, sign_status=4).last() result = xsign_app_download_url_signal.send(None, app_pk=app_obj.get('pk'), udid=udid,
if appudid_obj: download_url_type=download_url_type, limit=limit)
super_sign_obj = APPSuperSignUsedInfo.objects.filter(udid__udid__udid=udid, return result[0][1]
app_id_id=app_obj.get("pk"),
developerid__status__in=Config.DEVELOPER_USE_STATUS).last()
if super_sign_obj and super_sign_obj.user_id.supersign_active:
app_to_developer_obj = APPToDeveloper.objects.filter(app_id_id=app_obj.get("pk"),
developerid=super_sign_obj.developerid).last()
if app_to_developer_obj:
release_obj = AppReleaseInfo.objects.filter(app_id_id=app_obj.get("pk"), is_master=True).last()
if release_obj.release_id == app_to_developer_obj.release_file:
binary_file = app_to_developer_obj.binary_file
else:
binary_file = app_to_developer_obj.release_file
return local_storage.get_download_url(
binary_file + "." + download_url_type, limit), ""
else:
return "", ""
else:
return "", ""
else:
return "", ""
supersign = Config.DEFAULT_MOBILEPROVISION.get("supersign") supersign = Config.DEFAULT_MOBILEPROVISION.get("supersign")
mobileconifg = "" mobileconifg = ""

@ -20,20 +20,22 @@ from django.views.static import serve
from admin.views.celery_flower import CeleryFlowerView from admin.views.celery_flower import CeleryFlowerView
from api.views.download import DownloadView, InstallView from api.views.download import DownloadView, InstallView
from fir_ser import settings from fir_ser import settings
from xsign.views.download import XsignDownloadView
from xsign.views.receiveudids import IosUDIDView, ShowUdidView from xsign.views.receiveudids import IosUDIDView, ShowUdidView
urlpatterns = [ urlpatterns = [
re_path('fly.admin/', admin.site.urls), re_path('fly.admin/', admin.site.urls),
re_path("api/v1/fir/server/", include('api.urls')), re_path("api/v1/fir/server/", include('api.urls')),
re_path("api/v1/fir/xsign/", include('xsign.urls')), re_path("api/v1/fir/xsign/", include('xsign.urls')),
re_path(r"xdownload/(?P<filename>\w+\.\w+)$", XsignDownloadView.as_view(), name="xdownload"),
re_path("api/v2/fir/server/", include('cli.urls')), re_path("api/v2/fir/server/", include('cli.urls')),
re_path("api/v3/fir/server/", include('admin.urls')), re_path("api/v3/fir/server/", include('admin.urls')),
re_path('^captcha/', include('captcha.urls')), re_path('^captcha/', include('captcha.urls')),
# media路径配置 # media路径配置
re_path('files/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}), re_path('files/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}),
re_path("download/(?P<filename>\w+\.\w+)$", DownloadView.as_view(), name="download"), re_path(r"download/(?P<filename>\w+\.\w+)$", DownloadView.as_view(), name="download"),
re_path("install/(?P<app_id>\w+)$", InstallView.as_view(), name="install"), re_path(r"install/(?P<app_id>\w+)$", InstallView.as_view(), name="install"),
re_path("^udid/(?P<short>\w+)$", IosUDIDView.as_view()), re_path(r"^udid/(?P<short>\w+)$", IosUDIDView.as_view()),
re_path("^show_udid$", ShowUdidView.as_view()), re_path("^show_udid$", ShowUdidView.as_view()),
re_path(r'flower/(?P<path>.*)', CeleryFlowerView.as_view()), re_path(r'flower/(?P<path>.*)', CeleryFlowerView.as_view()),
] ]

@ -0,0 +1,52 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# author: NinEveN
# date: 2022/2/15
import logging
from django.dispatch import Signal, receiver
from api.models import AppReleaseInfo
from common.core.sysconfig import Config
from common.libs.storage.localApi import LocalStorage
from xsign.models import AppUDID, APPToDeveloper, APPSuperSignUsedInfo
logger = logging.getLogger(__name__)
"""
xsign 下载连接
"""
xsign_app_download_url_signal = Signal(providing_args=["app_pk", "udid", "download_url_type", "limit"])
@receiver(xsign_app_download_url_signal)
def xsign_app_download_url_callback(sender, **kwargs):
udid = kwargs.get('udid')
download_url_type = kwargs.get('download_url_type')
limit = kwargs.get('limit')
app_pk = kwargs.get('app_pk')
local_storage = LocalStorage(**Config.IOS_PMFILE_DOWNLOAD_DOMAIN)
appudid_obj = AppUDID.objects.filter(app_id_id=app_pk, udid__udid=udid, sign_status=4).last()
if appudid_obj:
super_sign_obj = APPSuperSignUsedInfo.objects.filter(udid__udid__udid=udid,
app_id_id=app_pk,
developerid__status__in=Config.DEVELOPER_USE_STATUS).last()
if super_sign_obj and super_sign_obj.user_id.supersign_active:
app_to_developer_obj = APPToDeveloper.objects.filter(app_id_id=app_pk,
developerid=super_sign_obj.developerid).last()
if app_to_developer_obj:
release_obj = AppReleaseInfo.objects.filter(app_id_id=app_pk, is_master=True).last()
if release_obj.release_id == app_to_developer_obj.release_file:
binary_file = app_to_developer_obj.binary_file
else:
binary_file = app_to_developer_obj.release_file
return local_storage.get_download_url(
binary_file + "." + download_url_type, limit, is_xsign=True), ""
else:
return "", ""
else:
return "", ""
else:
return "", ""

@ -20,54 +20,3 @@ def delete_app_to_dev_and_file(developer_obj, app_id):
storage = Storage(developer_obj.user_id) storage = Storage(developer_obj.user_id)
storage.delete_file(binary_file) storage.delete_file(binary_file)
app_to_developer_obj.delete() app_to_developer_obj.delete()
def make_resigned(bin_url, img_url, bundle_id, app_version, name):
ios_plist_tem = """<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0"><dict>
<key>items</key>
<array>
<dict>
<key>assets</key>
<array>
<dict>
<key>kind</key>
<string>software-package</string>
<key>url</key>
<string><![CDATA[{bin_url}]]></string>
</dict>
<dict>
<key>kind</key>
<string>display-image</string>
<key>needs-shine</key>
<integer>0</integer>
<key>url</key>
<string><![CDATA[{img_url}]]></string>
</dict>
<dict>
<key>kind</key>
<string>full-size-image</string>
<key>needs-shine</key>
<true/>
<key>url</key>
<string><![CDATA[{img_url}]]></string>
</dict>
</array>
<key>metadata</key>
<dict>
<key>bundle-identifier</key>
<string>{bundle_id}</string>
<key>bundle-version</key>
<string><![CDATA[{app_version}]]></string>
<key>kind</key>
<string>software</string>
<key>title</key>
<string><![CDATA[{name}]]></string>
</dict>
</dict>
</array>
</dict>
</plist>""".format(bin_url=bin_url, img_url=img_url, bundle_id=bundle_id, app_version=app_version, name=name)
logger.info(
f"make_resigned bin_url {bin_url} ,img_url {img_url}, bundle_id {bundle_id}, app_version {app_version}, name {name}")
return ios_plist_tem

@ -10,7 +10,7 @@ import os
from rest_framework.views import APIView from rest_framework.views import APIView
from api.models import AppReleaseInfo from api.models import AppReleaseInfo
from common.base.baseutils import get_profile_full_path, make_random_uuid, get_server_domain_from_request from common.base.baseutils import get_profile_full_path, make_random_uuid, get_server_domain_from_request, make_resigned
from common.core.response import ApiResponse, file_response, mobileprovision_file_response from common.core.response import ApiResponse, file_response, mobileprovision_file_response
from common.core.sysconfig import Config from common.core.sysconfig import Config
from common.utils.storage import Storage, get_local_storage from common.utils.storage import Storage, get_local_storage
@ -18,7 +18,6 @@ from common.utils.token import verify_token
from fir_ser import settings from fir_ser import settings
from xsign.models import APPToDeveloper, APPSuperSignUsedInfo from xsign.models import APPToDeveloper, APPSuperSignUsedInfo
from xsign.utils.supersignutils import make_sign_udid_mobile_config from xsign.utils.supersignutils import make_sign_udid_mobile_config
from xsign.utils.utils import make_resigned
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -29,7 +28,7 @@ def get_post_udid_url(request, short):
return "/".join(path_info_lists) return "/".join(path_info_lists)
class DownloadView(APIView): class XsignDownloadView(APIView):
""" """
文件下载接口,适用于本地存储和所有plist文件下载 文件下载接口,适用于本地存储和所有plist文件下载
""" """

Loading…
Cancel
Save