优化代码,增加超级签密钥证书获取教程

dependabot/pip/fir_ser/django-3.2.4
youngS 4 years ago
parent 56cd35565f
commit 1cc239698b
  1. BIN
      fir_client/src/assets/sign/help/sign_help_0.png
  2. BIN
      fir_client/src/assets/sign/help/sign_help_1.png
  3. BIN
      fir_client/src/assets/sign/help/sign_help_2.png
  4. BIN
      fir_client/src/assets/sign/help/sign_help_3.png
  5. BIN
      fir_client/src/assets/sign/help/sign_help_4.png
  6. BIN
      fir_client/src/assets/sign/help/sign_help_5.png
  7. 7
      fir_client/src/components/apps/FirApps.vue
  8. 4
      fir_client/src/components/index/FirIndexBody.vue
  9. 33
      fir_client/src/components/user/FirSuperSignBase.vue
  10. 43
      fir_client/src/components/user/FirSuperSignHelp.vue
  11. 7
      fir_client/src/router/index.js
  12. 7
      fir_ser/api/models.py
  13. 2
      fir_ser/api/utils/app/iossignapi.py
  14. 19
      fir_ser/api/utils/app/supersignutils.py
  15. 7
      fir_ser/api/utils/crontab/ctasks.py
  16. 15
      fir_ser/api/utils/serializer.py
  17. 4
      fir_ser/api/utils/storage/aliyunApi.py
  18. 3
      fir_ser/api/views/apps.py
  19. 4
      fir_ser/api/views/uploads.py
  20. 6
      fir_ser/fir_ser/settings.py

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

@ -594,12 +594,19 @@
delete this.analyseappinfo.icon; delete this.analyseappinfo.icon;
this.$message.success(file.name + '上传成功'); this.$message.success(file.name + '上传成功');
this.analyseappinfo.short = this.short; this.analyseappinfo.short = this.short;
const loading = this.$loading({
lock: true,
text: '应用入库中,请耐心等待',
spinner: 'el-icon-loading',
// background: 'rgba(0, 0, 0, 0.7)'
});
analyseApps(data => { analyseApps(data => {
if (data.code === 1000) { if (data.code === 1000) {
let app_uuid = this.analyseappinfo.app_uuid; let app_uuid = this.analyseappinfo.app_uuid;
this.closeUpload(); this.closeUpload();
this.$router.push({name: 'FirAppInfostimeline', params: {id: app_uuid}}); this.$router.push({name: 'FirAppInfostimeline', params: {id: app_uuid}});
} }
loading.close()
}, {'methods': 'PUT', 'data': this.analyseappinfo}); }, {'methods': 'PUT', 'data': this.analyseappinfo});
} }
}, },

@ -8,8 +8,6 @@
<div class="topplayer-top"> <div class="topplayer-top">
<div class="word">{{ item.title }}</div> <div class="word">{{ item.title }}</div>
<div class="content">{{ item.content }}</div> <div class="content">{{ item.content }}</div>
<!-- <el-button @click="$router.push({name:'FirApps'})">开始分发 &gt;</el-button>-->
</div> </div>
</div> </div>
</el-carousel-item> </el-carousel-item>
@ -29,7 +27,7 @@
<div class="server-block" <div class="server-block"
onmouseenter="this.style.color='#28f';this.style.borderColor='#28f'" onmouseenter="this.style.color='#28f';this.style.borderColor='#28f'"
onmouseleave="this.style.color='#666';this.style.borderColor='#ccc'"> onmouseleave="this.style.color='#666';this.style.borderColor='#ccc'">
<img class="center-block" :src="item.logo" alt="logo"> <img class="center-block" v-lazy="item.logo" alt="logo">
<p class="text-center">{{item.title}}</p> <p class="text-center">{{item.title}}</p>
<div <div
class="text-center" class="text-center"

@ -23,8 +23,8 @@
</el-form-item> </el-form-item>
</div> </div>
<el-form-item label-width="110px" label="设备数量"> <el-form-item label-width="110px" label="设备数量" style="text-align: left">
<el-input v-model="editdeveloperinfo.usable_number"/> <el-input-number v-model="editdeveloperinfo.usable_number" :min="0" :max="100" label="设备数量"></el-input-number>
</el-form-item> </el-form-item>
<el-form-item label-width="110px" label="备注"> <el-form-item label-width="110px" label="备注">
@ -219,8 +219,8 @@
</el-form-item> </el-form-item>
</div> </div>
<el-form-item label-width="110px" label="设备数量"> <el-form-item label-width="110px" label="设备数量" style="text-align: left">
<el-input v-model="editdeveloperinfo.usable_number"/> <el-input-number v-model="editdeveloperinfo.usable_number" :min="0" :max="100" label="设备数量"></el-input-number>
</el-form-item> </el-form-item>
<el-form-item label-width="110px" label="备注"> <el-form-item label-width="110px" label="备注">
@ -232,6 +232,21 @@
</div> </div>
</el-form> </el-form>
<el-card style="margin-top: 20px;text-align: left" header="获取密钥帮助">
<h1>获取密钥</h1>
<p>前往 AppStore Connect 按照
<el-button plain type="primary" size="small" @click="$router.push({name:'FirSuperSignHelp'})">
此步骤
</el-button>
获取 API 密钥将获取到的密钥添加到这里
</p>
<h1>注意事项</h1>
<p>1.添加后请勿撤销 API 密钥否则会导致用户安装的软件闪退或无法安装</p>
<p>2.每个开发者账号最多可创建两本证书请确保至少还可以创建一本证书</p>
<p>3.添加后系统会自动创建证书设备和描述文件请勿删除这些文件否则会导致用户安装的软件闪退或无法安装</p>
</el-card>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="设备消耗" name="useddevices"> <el-tab-pane label="设备消耗" name="useddevices">
<el-input <el-input
@ -410,7 +425,7 @@
appidseach: "", appidseach: "",
dialogaddDeveloperVisible: false, dialogaddDeveloperVisible: false,
title: "", title: "",
editdeveloperinfo: {auth_type: 0}, editdeveloperinfo: {auth_type: 0, usable_number: 100},
isedit: false, isedit: false,
placeholder: "", placeholder: "",
pagination: {"currentPage": 1, "total": 0, "pagesize": 10}, pagination: {"currentPage": 1, "total": 0, "pagesize": 10},
@ -474,7 +489,7 @@
}, },
canceledit() { canceledit() {
this.dialogaddDeveloperVisible = false; this.dialogaddDeveloperVisible = false;
this.editdeveloperinfo = {auth_type: 0}; this.editdeveloperinfo = {auth_type: 0,usable_number:100};
this.isedit = false; this.isedit = false;
this.placeholder = "" this.placeholder = ""
}, },
@ -586,7 +601,11 @@
if (data.use_num) { if (data.use_num) {
this.developer_used_info = data.use_num; this.developer_used_info = data.use_num;
if (this.developer_used_info.all_usable_number !== 0) { if (this.developer_used_info.all_usable_number !== 0) {
this.percentage = parseInt(this.developer_used_info.flyapp_used_sum * 100 / this.developer_used_info.all_usable_number); let p = parseInt(this.developer_used_info.flyapp_used_sum * 100 / this.developer_used_info.all_usable_number);
if (p < 0 || p >= 100) {
p = 100
}
this.percentage = p;
} }
} }

@ -0,0 +1,43 @@
<template>
<el-main>
<h1> 请点击打开 <a href="https://appstoreconnect.apple.com/" target="_blank">appstoreconnect</a> 登录苹果开发者账户进行操作</h1>
<div v-for="helpic in imagelist" :key="helpic">
<img v-lazy="helpic" alt="" style="width: 1100px;margin-top: 20px"/>
</div>
</el-main>
</template>
<script>
import {getUserInfoFun} from "@/utils";
export default {
name: "FirSuperSignHelp",
data() {
return {
imagelist: [
require('@/assets/sign/help/sign_help_0.png'),
require('@/assets/sign/help/sign_help_1.png'),
require('@/assets/sign/help/sign_help_2.png'),
require('@/assets/sign/help/sign_help_3.png'),
require('@/assets/sign/help/sign_help_4.png'),
require('@/assets/sign/help/sign_help_5.png'),
]
}
}, mounted() {
getUserInfoFun(this);
}
}
</script>
<style scoped>
.el-main {
margin: 20px auto 100px;
width: 1166px;
position: relative;
padding-bottom: 1px;
text-align: center;
color: #9b9b9b;
-webkit-font-smoothing: antialiased;
border-radius: 1%;
}
</style>

@ -152,7 +152,12 @@ const router = new VueRouter({
meta: {label: '订单详情'}, meta: {label: '订单详情'},
component: () => import("@/components/user/FirUserOrders"), component: () => import("@/components/user/FirUserOrders"),
}, },
{
path: 'supersign-help',
name: 'FirSuperSignHelp',
meta: {label: '密钥获取帮助'},
component: () => import("@/components/user/FirSuperSignHelp"),
}
] ]
}, },
{ {

@ -261,6 +261,13 @@ class AppIOSDeveloperInfo(models.Model):
verbose_name_plural = "苹果开发者账户" verbose_name_plural = "苹果开发者账户"
unique_together = (('user_id', 'issuer_id'),) unique_together = (('user_id', 'issuer_id'),)
def save(self, *args, **kwargs):
if self.usable_number > 100:
self.usable_number = 100
elif self.usable_number < 0:
self.usable_number = 0
return super(AppIOSDeveloperInfo, self).save(*args, **kwargs)
def __str__(self): def __str__(self):
return "%s-%s" % (self.user_id, self.issuer_id) return "%s-%s" % (self.user_id, self.issuer_id)

@ -105,7 +105,7 @@ class AppDeveloperApiV2(object):
req.get_subject().L = 'BJ' req.get_subject().L = 'BJ'
req.get_subject().ST = 'BJ' req.get_subject().ST = 'BJ'
req.get_subject().C = 'CN' req.get_subject().C = 'CN'
req.get_subject().emailAddress = 'fly@fly.com' req.get_subject().emailAddress = 'flyapps@126.com'
req.set_pubkey(key) req.set_pubkey(key)
req.sign(key, 'sha256') req.sign(key, 'sha256')
csr_content = dump_certificate_request(FILETYPE_PEM, req) csr_content = dump_certificate_request(FILETYPE_PEM, req)

@ -7,7 +7,7 @@
import uuid, xmltodict, os, re, logging, time import uuid, xmltodict, os, re, logging, time
from api.utils.response import BaseResponse from api.utils.response import BaseResponse
from fir_ser.settings import SUPER_SIGN_ROOT, MEDIA_ROOT, SERVER_DOMAIN, MOBILECONFIG_SIGN_SSL from fir_ser.settings import SUPER_SIGN_ROOT, MEDIA_ROOT, SERVER_DOMAIN, MOBILECONFIG_SIGN_SSL, MSGTEMPLATE
from api.utils.app.iossignapi import ResignApp, AppDeveloperApiV2 from api.utils.app.iossignapi import ResignApp, AppDeveloperApiV2
from api.models import APPSuperSignUsedInfo, AppUDID, AppIOSDeveloperInfo, AppReleaseInfo, Apps, APPToDeveloper, \ from api.models import APPSuperSignUsedInfo, AppUDID, AppIOSDeveloperInfo, AppReleaseInfo, Apps, APPToDeveloper, \
UDIDsyncDeveloper, DeveloperAppID, DeveloperDevicesID UDIDsyncDeveloper, DeveloperAppID, DeveloperDevicesID
@ -37,6 +37,7 @@ def check_org_file(user_obj, org_file):
def resign_by_app_id(app_obj, need_download_profile=True): def resign_by_app_id(app_obj, need_download_profile=True):
user_obj = app_obj.user_id user_obj = app_obj.user_id
info_list = []
if app_obj.issupersign and user_obj.supersign_active: if app_obj.issupersign and user_obj.supersign_active:
for dappid_obj in DeveloperAppID.objects.filter(app_id=app_obj).all(): for dappid_obj in DeveloperAppID.objects.filter(app_id=app_obj).all():
developer_obj = dappid_obj.developerid developer_obj = dappid_obj.developerid
@ -49,7 +50,10 @@ def resign_by_app_id(app_obj, need_download_profile=True):
else: else:
download_flag = True download_flag = True
with cache.lock("%s_%s_%s" % ('run_sign', app_obj.app_id, developer_obj.issuer_id), timeout=60 * 10): with cache.lock("%s_%s_%s" % ('run_sign', app_obj.app_id, developer_obj.issuer_id), timeout=60 * 10):
IosUtils.run_sign(user_obj, app_obj, developer_obj, download_flag, None, d_time, {}, True) status, result = IosUtils.run_sign(user_obj, app_obj, developer_obj, download_flag, None, d_time, {},
True)
info_list.append({'developer_id': developer_obj.issuer_id, 'result': (status, result)})
return info_list
def check_app_sign_limit(app_obj): def check_app_sign_limit(app_obj):
@ -243,9 +247,9 @@ class IosUtils(object):
if self.user_obj.email: if self.user_obj.email:
if send_msg_over_limit("get", self.user_obj.email): if send_msg_over_limit("get", self.user_obj.email):
send_msg_over_limit("set", self.user_obj.email) send_msg_over_limit("set", self.user_obj.email)
send_ios_developer_active_status(self.user_obj, send_ios_developer_active_status(self.user_obj, MSGTEMPLATE.get('NOT_EXIST_DEVELOPER', '')
'user %s app %s sign failed. has not exists enabled developer' % ( % (
self.user_obj, self.app_obj)) self.user_obj.first_name, self.app_obj.name))
else: else:
logger.error("user %s send msg failed. over limit" % self.user_obj) logger.error("user %s send msg failed. over limit" % self.user_obj)
@ -341,8 +345,9 @@ class IosUtils(object):
developer_obj.is_actived = False developer_obj.is_actived = False
developer_obj.save() developer_obj.save()
send_ios_developer_active_status(developer_obj.user_id, send_ios_developer_active_status(developer_obj.user_id,
'app %s developer %s sign failed %s. disable this developer' % ( MSGTEMPLATE.get('ERROR_DEVELOPER') % (
app_obj, developer_obj, result)) developer_obj.user_id.first_name, app_obj.name,
developer_obj.issuer_id))
return False, result return False, result
if not developer_app_id and result.get("aid", None): if not developer_app_id and result.get("aid", None):

@ -9,7 +9,7 @@ from api.utils.storage.storage import Storage
from api.utils.app.supersignutils import IosUtils from api.utils.app.supersignutils import IosUtils
from api.utils.utils import send_ios_developer_active_status from api.utils.utils import send_ios_developer_active_status
from django.core.cache import cache from django.core.cache import cache
from fir_ser.settings import CACHE_KEY_TEMPLATE, SYNC_CACHE_TO_DATABASE, SUPER_SIGN_ROOT from fir_ser.settings import CACHE_KEY_TEMPLATE, SYNC_CACHE_TO_DATABASE, SUPER_SIGN_ROOT, MSGTEMPLATE
import time, os import time, os
import logging import logging
@ -67,11 +67,12 @@ def auto_check_ios_developer_active():
if userinfo.supersign_active: if userinfo.supersign_active:
status, result = IosUtils.active_developer(ios_developer) status, result = IosUtils.active_developer(ios_developer)
msg = "auto_check_ios_developer_active user:%s ios.developer:%s status:%s result:%s" % ( msg = "auto_check_ios_developer_active user:%s ios.developer:%s status:%s result:%s" % (
ios_developer.user_id, ios_developer, status, result) userinfo, ios_developer, status, result)
if status: if status:
logger.info(msg) logger.info(msg)
else: else:
ios_developer.is_actived = False ios_developer.is_actived = False
ios_developer.save() ios_developer.save()
logger.error(msg) logger.error(msg)
send_ios_developer_active_status(ios_developer.user_id, msg) send_ios_developer_active_status(userinfo, MSGTEMPLATE.get('AUTO_CHECK_DEVELOPER') % (
userinfo.first_name, ios_developer.name))

@ -15,7 +15,7 @@ token_obj = DownloadToken()
def get_download_url_from_context(self, obj, key, url, force_new=False): def get_download_url_from_context(self, obj, key, url, force_new=False):
icon_url = "" download_url = ""
if self.context.get("key", None) and self.context.get("key") != "undefined": if self.context.get("key", None) and self.context.get("key") != "undefined":
key = self.context.get("key", '') key = self.context.get("key", '')
if self.context.get("storage", None) and self.context.get("storage") != "undefined": if self.context.get("storage", None) and self.context.get("storage") != "undefined":
@ -25,11 +25,15 @@ def get_download_url_from_context(self, obj, key, url, force_new=False):
storage = Storage(obj.user_id) storage = Storage(obj.user_id)
elif isinstance(obj, models.AppReleaseInfo): elif isinstance(obj, models.AppReleaseInfo):
storage = Storage(obj.app_id.user_id) storage = Storage(obj.app_id.user_id)
elif isinstance(obj, models.UserInfo):
storage = Storage(obj)
else: else:
storage = None storage = None
if storage: if storage:
icon_url = storage.get_download_url(os.path.basename(url), 600, key, force_new) download_url = storage.get_download_url(os.path.basename(url), 600, key, force_new)
return icon_url logger.info(
'get %s download_url %s force_new:%s key:%s' % (os.path.basename(url), download_url, force_new, key))
return download_url
def get_app_master_obj_from_context(self, obj): def get_app_master_obj_from_context(self, obj):
@ -59,8 +63,7 @@ class UserInfoSerializer(serializers.ModelSerializer):
head_img = serializers.SerializerMethodField() head_img = serializers.SerializerMethodField()
def get_head_img(self, obj): def get_head_img(self, obj):
storage = Storage(obj) return get_download_url_from_context(self, obj, '', obj.head_img)
return storage.get_download_url(obj.head_img)
free_download_times = serializers.SerializerMethodField() free_download_times = serializers.SerializerMethodField()
@ -315,7 +318,7 @@ class AppReleaseSerializer(serializers.ModelSerializer):
return token_obj.make_token(obj.release_id, 600) return token_obj.make_token(obj.release_id, 600)
def get_icon_url(self, obj): def get_icon_url(self, obj):
return get_download_url_from_context(self, obj, '', os.path.basename(obj.icon_url), force_new=False) return get_download_url_from_context(self, obj, '', os.path.basename(obj.icon_url))
def get_master_color(self, obj): def get_master_color(self, obj):
if obj.is_master: if obj.is_master:

@ -113,8 +113,8 @@ class AliYunOss(object):
self.domain_name = domain_name self.domain_name = domain_name
self.bucket_get = None self.bucket_get = None
self.bucket = None self.bucket = None
self.make_auth_bucket('init_get', 900, True) self.make_auth_bucket('init_get', 1800, True)
self.make_auth_bucket('init_auth', 900) self.make_auth_bucket('init_auth', 1800)
def fetch_sts_token(self, name, expires, only_put=False, only_get=False): def fetch_sts_token(self, name, expires, only_put=False, only_get=False):
"""子用户角色扮演获取临时用户的密钥 """子用户角色扮演获取临时用户的密钥

@ -226,7 +226,8 @@ class AppInfoView(APIView):
if do_sign_flag == 2: if do_sign_flag == 2:
c_task = run_resign_task.apply_async((apps_obj.app_id, False)) c_task = run_resign_task.apply_async((apps_obj.app_id, False))
if c_task: if c_task:
c_task.get(propagate=False) msg = c_task.get(propagate=False)
logger.info("app %s run_resign_task msg:%s" % (apps_obj, msg))
if c_task.successful(): if c_task.successful():
c_task.forget() c_task.forget()
del_cache_response_by_short(apps_obj.app_id) del_cache_response_by_short(apps_obj.app_id)

@ -120,7 +120,9 @@ class AppAnalyseView(APIView):
app_info = Apps.objects.filter(bundle_id=data.get("bundleid")).first() app_info = Apps.objects.filter(bundle_id=data.get("bundleid")).first()
if app_info: if app_info:
if app_info.issupersign and app_info.user_id.supersign_active: if app_info.issupersign and app_info.user_id.supersign_active:
c_task = run_resign_task.apply_async((app_info.app_id, False)).get(propagate=False) c_task = run_resign_task.apply_async((app_info.app_id, False))
msg = c_task.get(propagate=False)
logger.info("app %s run_resign_task msg:%s" % (app_info, msg))
if c_task.successful(): if c_task.successful():
c_task.forget() c_task.forget()
else: else:

@ -582,3 +582,9 @@ CELERY_BEAT_SCHEDULE = {
'one_off': True 'one_off': True
}, },
} }
MSGTEMPLATE = {
'NOT_EXIST_DEVELOPER': '用户 %s 你好,应用 %s 签名失败了,苹果开发者总设备量已经超限,请添加新的苹果开发者或者修改开发者设备数量。感谢有你!',
'ERROR_DEVELOPER': '用户 %s 你好,应用 %s 签名失败了,苹果开发者 %s 信息异常,请重新检查苹果开发者状态是否正常。感谢有你!',
'AUTO_CHECK_DEVELOPER': '用户 %s 你好,苹果开发者 %s 信息异常,请重新检查苹果开发者状态是否正常。感谢有你!',
}

Loading…
Cancel
Save