Merge branch 'super_signature'

pull/1/head
xiaoyu 4 years ago
commit 5f58e88ebb
  1. 7
      fir_ser/api/utils/app/iossignapi.py
  2. 46
      fir_ser/api/utils/app/supersignutils.py
  3. 9
      fir_ser/api/utils/crontab/run.py
  4. 18
      fir_ser/api/utils/crontab/sync_cache.py
  5. 4
      fir_ser/api/views/download.py
  6. 11
      fir_ser/fir_ser/settings.py

@ -111,6 +111,13 @@ class ResignApp(object):
# script_path=os.path.join(SUPER_SIGN_ROOT,'scripts','apple_api.rb') # script_path=os.path.join(SUPER_SIGN_ROOT,'scripts','apple_api.rb')
self.cmd = "isign -c '%s' -k '%s' " % (self.app_dev_pem, self.my_local_key) self.cmd = "isign -c '%s' -k '%s' " % (self.app_dev_pem, self.my_local_key)
@staticmethod
def sign_mobileconfig(mobilconfig_path, sign_mobilconfig_path, ssl_pem_path, ssl_key_path):
cmd = "openssl smime -sign -in %s -out %s -signer %s " \
"-inkey %s -certfile %s -outform der -nodetach " % (
mobilconfig_path, sign_mobilconfig_path, ssl_pem_path, ssl_key_path, ssl_pem_path)
return exec_shell(cmd)
def sign(self, new_profile, org_ipa, new_ipa): def sign(self, new_profile, org_ipa, new_ipa):
self.cmd = self.cmd + " -p '%s' -o '%s' '%s'" % (new_profile, new_ipa, org_ipa) self.cmd = self.cmd + " -p '%s' -o '%s' '%s'" % (new_profile, new_ipa, org_ipa)
result = exec_shell(self.cmd) result = exec_shell(self.cmd)

@ -5,7 +5,7 @@
# date: 2020/3/6 # date: 2020/3/6
import uuid, xmltodict, os, re, logging import uuid, xmltodict, os, re, logging
from fir_ser.settings import SUPER_SIGN_ROOT, MEDIA_ROOT, SERVER_DOMAIN from fir_ser.settings import SUPER_SIGN_ROOT, MEDIA_ROOT, SERVER_DOMAIN, MOBILECONFIG_SIGN_SSL
from api.utils.app.iossignapi import AppDeveloperApi, ResignApp from api.utils.app.iossignapi import AppDeveloperApi, ResignApp
from api.models import APPSuperSignUsedInfo, AppUDID, AppIOSDeveloperInfo, AppReleaseInfo, Apps, APPToDeveloper, \ from api.models import APPSuperSignUsedInfo, AppUDID, AppIOSDeveloperInfo, AppReleaseInfo, Apps, APPToDeveloper, \
UDIDsyncDeveloper UDIDsyncDeveloper
@ -32,8 +32,45 @@ def udid_bytes_to_dict(xml_stream):
return new_uuid_info return new_uuid_info
def make_udid_mobileconfig(udid_url, PayloadOrganization, PayloadUUID=uuid.uuid1(), PayloadDescription='本文件仅用来获取设备ID', def make_sign_udid_mobileconfig(udid_url, PayloadOrganization, appname):
PayloadDisplayName='查询设备UDID'): if MOBILECONFIG_SIGN_SSL.get("open"):
ssl_key_path = MOBILECONFIG_SIGN_SSL.get("ssl_key_path", None)
ssl_pem_path = MOBILECONFIG_SIGN_SSL.get("ssl_pem_path", None)
if ssl_key_path and ssl_pem_path and os.path.isfile(ssl_key_path) and os.path.isfile(ssl_pem_path):
mobileconfig_tmp_dir = os.path.join(SUPER_SIGN_ROOT, 'tmp', 'mobileconfig')
if not os.path.exists(mobileconfig_tmp_dir):
os.makedirs(mobileconfig_tmp_dir)
mobileconfig_filename = PayloadOrganization + str(uuid.uuid1())
mobilconfig_path = os.path.join(mobileconfig_tmp_dir, mobileconfig_filename)
sign_mobilconfig_path = os.path.join(mobileconfig_tmp_dir, 'sign_' + mobileconfig_filename)
with open(mobilconfig_path, "w") as f:
f.write(make_udid_mobileconfig(udid_url, PayloadOrganization, appname))
status, result = ResignApp.sign_mobileconfig(mobilconfig_path, sign_mobilconfig_path, ssl_pem_path,
ssl_key_path)
if status:
mobileconfig_body = open(sign_mobilconfig_path, 'rb')
else:
logger.error(
"%s %s sign_mobileconfig failed ERROR:%s" % (PayloadOrganization, appname, result.get("err_info")))
return make_udid_mobileconfig(udid_url, PayloadOrganization, appname)
return mobileconfig_body
else:
logger.error("sign_mobileconfig %s or %s is not exists" % (ssl_key_path, ssl_pem_path))
return make_udid_mobileconfig(udid_url, PayloadOrganization, appname)
else:
return make_udid_mobileconfig(udid_url, PayloadOrganization, appname)
def make_udid_mobileconfig(udid_url, PayloadOrganization, appname, PayloadUUID=uuid.uuid1(),
PayloadDescription='该文件仅用来获取设备ID,帮助用户安装授权',
PayloadDisplayName='设备安装授权'):
# <!--参考:https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/iPhoneOTAConfiguration/ConfigurationProfileExamples/ConfigurationProfileExamples.html--> # <!--参考:https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/iPhoneOTAConfiguration/ConfigurationProfileExamples/ConfigurationProfileExamples.html-->
mobileconfig = '''<?xml version="1.0" encoding="UTF-8"?> mobileconfig = '''<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@ -68,7 +105,8 @@ def make_udid_mobileconfig(udid_url, PayloadOrganization, PayloadUUID=uuid.uuid1
<key>PayloadType</key> <key>PayloadType</key>
<string>Profile Service</string> <string>Profile Service</string>
</dict> </dict>
</plist>''' % (udid_url, PayloadOrganization, PayloadDisplayName, PayloadUUID, PayloadOrganization, PayloadDescription) </plist>''' % (udid_url, PayloadOrganization, appname + " -- " + PayloadDisplayName, PayloadUUID, PayloadOrganization,
PayloadDescription)
return mobileconfig return mobileconfig

@ -7,7 +7,8 @@
from apscheduler.schedulers.background import BackgroundScheduler from apscheduler.schedulers.background import BackgroundScheduler
from django_apscheduler.jobstores import DjangoJobStore, register_events, register_job from django_apscheduler.jobstores import DjangoJobStore, register_events, register_job
from fir_ser.settings import SYNC_CACHE_TO_DATABASE from fir_ser.settings import SYNC_CACHE_TO_DATABASE
from api.utils.crontab.sync_cache import sync_download_times, auto_clean_upload_tmp_file, auto_delete_job_log from api.utils.crontab.sync_cache import sync_download_times, auto_clean_upload_tmp_file, auto_delete_job_log, \
auto_delete_tmp_file
import logging import logging
logger = logging.getLogger(__file__) logger = logging.getLogger(__file__)
@ -40,11 +41,15 @@ try:
# @register_job(scheduler, 'cron', day_of_week='mon-fri', hour='9', minute='30', second='10',id='task_time') # @register_job(scheduler, 'cron', day_of_week='mon-fri', hour='9', minute='30', second='10',id='task_time')
@register_job(scheduler, "interval", seconds=SYNC_CACHE_TO_DATABASE.get("auto_clean_tmp_file_times")) @register_job(scheduler, "interval", seconds=SYNC_CACHE_TO_DATABASE.get("auto_clean_tmp_file_times"))
def auto_clean_upload_tmp_file_job(): def auto_clean_upload_tmp_file_job():
# 这里写你要执行的任务
auto_clean_upload_tmp_file() auto_clean_upload_tmp_file()
auto_delete_job_log() auto_delete_job_log()
@register_job(scheduler, "interval", seconds=SYNC_CACHE_TO_DATABASE.get("auto_clean_local_tmp_file_times"))
def auto_delete_tmp_file_job():
auto_delete_tmp_file()
register_events(scheduler) register_events(scheduler)
scheduler.start() scheduler.start()
except Exception as e: except Exception as e:

@ -7,8 +7,8 @@
from api.models import Apps, UserInfo from api.models import Apps, UserInfo
from api.utils.storage.storage import Storage from api.utils.storage.storage import Storage
from django.core.cache import cache from django.core.cache import cache
from fir_ser.settings import CACHE_KEY_TEMPLATE, SYNC_CACHE_TO_DATABASE from fir_ser.settings import CACHE_KEY_TEMPLATE, SYNC_CACHE_TO_DATABASE, SUPER_SIGN_ROOT
import time import time, os
from django_apscheduler.models import DjangoJobExecution from django_apscheduler.models import DjangoJobExecution
import logging import logging
@ -65,3 +65,17 @@ def auto_delete_job_log():
count = DjangoJobExecution.objects.count() count = DjangoJobExecution.objects.count()
if count > need_count: if count > need_count:
DjangoJobExecution.objects.filter(id__lte=max_id - need_count).delete() DjangoJobExecution.objects.filter(id__lte=max_id - need_count).delete()
def auto_delete_tmp_file():
mobileconfig_tmp_dir = os.path.join(SUPER_SIGN_ROOT, 'tmp', 'mobileconfig')
for root, dirs, files in os.walk(mobileconfig_tmp_dir, topdown=False):
now_time = time.time()
for name in files:
file_path = os.path.join(root, name)
st_mtime = os.stat(file_path).st_mtime
if now_time - st_mtime > SYNC_CACHE_TO_DATABASE.get('clean_local_tmp_file_from_mtime', 30 * 60):
try:
os.remove(file_path)
except Exception as e:
logger.error("auto_delete_tmp_file %s Failed . Exception %s" % (file_path, e))

@ -10,7 +10,7 @@ from fir_ser import settings
from api.utils.TokenManager import DownloadToken from api.utils.TokenManager import DownloadToken
from api.utils.app.randomstrings import make_random_uuid from api.utils.app.randomstrings import make_random_uuid
from api.utils.app.apputils import make_resigned from api.utils.app.apputils import make_resigned
from api.utils.app.supersignutils import make_udid_mobileconfig, get_post_udid_url, get_redirect_server_domain from api.utils.app.supersignutils import make_sign_udid_mobileconfig, get_post_udid_url, get_redirect_server_domain
from api.utils.storage.storage import Storage from api.utils.storage.storage import Storage
from api.utils.storage.caches import get_app_instance_by_cache, get_download_url_by_cache, set_app_download_by_cache, \ from api.utils.storage.caches import get_app_instance_by_cache, get_download_url_by_cache, set_app_download_by_cache, \
del_cache_response_by_short del_cache_response_by_short
@ -69,7 +69,7 @@ class DownloadView(APIView):
if release_obj: if release_obj:
bundle_id = release_obj.app_id.bundle_id bundle_id = release_obj.app_id.bundle_id
udid_url = get_post_udid_url(request, release_obj.app_id.short) udid_url = get_post_udid_url(request, release_obj.app_id.short)
ios_udid_mobileconfig = make_udid_mobileconfig(udid_url, bundle_id) ios_udid_mobileconfig = make_sign_udid_mobileconfig(udid_url, bundle_id, release_obj.app_id.name)
response = FileResponse(ios_udid_mobileconfig) response = FileResponse(ios_udid_mobileconfig)
response['Content-Type'] = "application/x-apple-aspen-config" response['Content-Type'] = "application/x-apple-aspen-config"
response['Content-Disposition'] = 'attachment; filename=' + make_random_uuid() + '.mobileconfig' response['Content-Disposition'] = 'attachment; filename=' + make_random_uuid() + '.mobileconfig'

@ -230,8 +230,10 @@ FILE_UPLOAD_TMP_KEY = ".tmp"
SYNC_CACHE_TO_DATABASE = { SYNC_CACHE_TO_DATABASE = {
'download_times': 10, # 下载次数同步时间 'download_times': 10, # 下载次数同步时间
'auto_clean_tmp_file_times': 60 * 30, # 定时清理上传失误生成的临时文件 'auto_clean_tmp_file_times': 60 * 30, # 定时清理上传失误生成的临时文件
'auto_clean_apscheduler_log': 100000, # 定时清理定时任务执行的日志,该参数为日志保留的数量 'auto_clean_local_tmp_file_times': 60 * 30, # 定时清理临时文件,现在包含超级签名描述临时文件
'try_login_times': 5, # 当天登录失败次数,超过该失败次数,锁定24小时 'try_login_times': 5, # 当天登录失败次数,超过该失败次数,锁定24小时
'auto_clean_apscheduler_log': 100000, # 定时清理定时任务执行的日志,该日志存在数据库中,该参数为日志保留的数量
'clean_local_tmp_file_from_mtime': 60 * 60, # 清理最后一次修改时间超过限制时间的临时文件,单位秒
} }
SERVER_DOMAIN = { SERVER_DOMAIN = {
@ -244,6 +246,13 @@ SERVER_DOMAIN = {
'FILE_UPLOAD_DOMAIN': 'https://fly.harmonygames.cn', # 本地文件上传域名,使用本地存储必须配置 'FILE_UPLOAD_DOMAIN': 'https://fly.harmonygames.cn', # 本地文件上传域名,使用本地存储必须配置
} }
MOBILECONFIG_SIGN_SSL = {
# 描述文件是否签名,默认是关闭状态;如果开启,并且ssl_key_path 和 ssl_pem_path 正常,则使用填写的ssl进行签名,否则默认不签名
'open': False,
'ssl_key_path': '/data/cert/fly.harmonygames.cn.key',
'ssl_pem_path': '/data/cert/fly.harmonygames.cn.pem'
}
SESSION_ENGINE = "django.contrib.sessions.backends.cache" SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "default" SESSION_CACHE_ALIAS = "default"

Loading…
Cancel
Save