publicsignpoll
youngS 3 years ago
parent abbe709d27
commit 9d3b5c582e
  1. 2
      fir_client/src/components/apps/FirAppInfossupersign.vue
  2. 10
      fir_client/src/components/user/FirSuperSignBase.vue
  3. 54
      fir_ser/api/migrations/0015_iosdeveloperpublicpoolbill_remoteclientinfo.py
  4. 49
      fir_ser/api/models.py
  5. 4
      fir_ser/api/tasks.py
  6. 5
      fir_ser/api/utils/app/apputils.py
  7. 3
      fir_ser/api/utils/app/iossignapi.py
  8. 27
      fir_ser/api/utils/app/randomstrings.py
  9. 110
      fir_ser/api/utils/app/supersignutils.py
  10. 117
      fir_ser/api/utils/baseutils.py
  11. 122
      fir_ser/api/utils/modelutils.py
  12. 44
      fir_ser/api/utils/serializer.py
  13. 2
      fir_ser/api/utils/storage/aliyunApi.py
  14. 3
      fir_ser/api/utils/storage/caches.py
  15. 3
      fir_ser/api/utils/utils.py
  16. 6
      fir_ser/api/views/apps.py
  17. 6
      fir_ser/api/views/domain.py
  18. 9
      fir_ser/api/views/download.py
  19. 3
      fir_ser/api/views/login.py
  20. 12
      fir_ser/api/views/receiveudids.py
  21. 16
      fir_ser/api/views/supersign.py
  22. 6
      fir_ser/api/views/uploads.py
  23. 2
      fir_ser/cli.py

@ -19,7 +19,7 @@
</el-switch>
</el-tooltip>
<el-button @click="clean_app" v-if="!currentapp.issupersign && currentapp.count !== 0"
style="margin-left: 20px" size="small" type="info" plain>清理开发者账户脏数据
style="margin-left: 20px" size="small" type="info" plain>清理该应用脏数据
</el-button>
<el-link v-else :underline="false" style="margin-left: 20px">超级签名iOS专用需要配置好苹果开发者账户方可开启</el-link>

@ -341,6 +341,11 @@
label="开发者ID"
width="200">
</el-table-column>
<el-table-column
v-if="$store.state.userinfo&&$store.state.userinfo.role == 3"
prop="other_uid"
label="被使用户uid">
</el-table-column>
<el-table-column
:formatter="deviceformatter"
prop="created_time"
@ -411,6 +416,11 @@
label="设备序列号"
width="150">
</el-table-column>
<el-table-column
v-if="$store.state.userinfo&&$store.state.userinfo.role == 3"
prop="other_uid"
label="被使用户uid">
</el-table-column>
<el-table-column
:formatter="deviceformatter"
prop="created_time"

@ -0,0 +1,54 @@
# Generated by Django 3.2.3 on 2021-10-29 18:59
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('api', '0014_alter_useraddisplayinfo_unique_together'),
]
operations = [
migrations.CreateModel(
name='RemoteClientInfo',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('remote_addr', models.GenericIPAddressField(verbose_name='远程IP地址')),
('user_agent', models.CharField(max_length=512, verbose_name='客户端agent')),
('method', models.CharField(max_length=16, verbose_name='请求方式')),
('uri_info', models.CharField(max_length=256, verbose_name='访问的URI')),
('a_domain', models.CharField(max_length=128, verbose_name='前端域名')),
('description', models.CharField(max_length=256, verbose_name='访问描述')),
('created_time', models.DateTimeField(auto_now_add=True, verbose_name='访问时间')),
],
options={
'verbose_name': '客户端访问记录',
'verbose_name_plural': '客户端访问记录',
},
),
migrations.CreateModel(
name='IosDeveloperPublicPoolBill',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('action', models.SmallIntegerField(choices=[(0, '消费'), (1, '充值'), (2, '转账')], default=0,
help_text='0 消费 1 充值 2 转账', verbose_name='资金类型')),
('number', models.IntegerField(default=1, verbose_name='消耗次数')),
('app_info', models.JSONField(blank=True, max_length=256, null=True, verbose_name='属于哪个APP')),
('udid_info', models.JSONField(blank=True, max_length=256, null=True, verbose_name='设备id信息')),
('developer_info', models.JSONField(blank=True, max_length=256, null=True, verbose_name='开发者信息')),
('description', models.CharField(blank=True, default='', max_length=128, verbose_name='操作描述')),
('created_time', models.DateTimeField(auto_now_add=True, verbose_name='添加时间')),
('to_user_id', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE,
related_name='to_user_id', to=settings.AUTH_USER_MODEL,
verbose_name='用户ID')),
('user_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='org_user_id',
to=settings.AUTH_USER_MODEL, verbose_name='用户ID')),
],
options={
'verbose_name': '资金流转账单',
'verbose_name_plural': '资金流转账单',
},
),
]

@ -3,9 +3,10 @@ from django.db import models
# Create your models here.
from django.contrib.contenttypes.models import ContentType
from api.utils.app.randomstrings import make_random_uuid
from django.contrib.auth.models import AbstractUser
from api.utils.TokenManager import generate_alphanumeric_token_of_length, generate_numeric_token_of_length
from api.utils.baseutils import make_random_uuid
######################################## 用户表 ########################################
@ -522,12 +523,44 @@ class UserAdDisplayInfo(models.Model):
class IosDeveloperPublicPoolBill(models.Model):
user_id = models.ForeignKey(to="UserInfo", verbose_name="用户ID", on_delete=models.CASCADE)
action_choices = ((0, 'used'), (1, 'add'))
action = models.SmallIntegerField(choices=action_choices, default=0, verbose_name="消费类型",
help_text="0 表示消耗 1表示充值")
user_id = models.ForeignKey(to="UserInfo", verbose_name="用户ID", on_delete=models.CASCADE,
related_name='org_user_id')
to_user_id = models.ForeignKey(to="UserInfo", verbose_name="用户ID", on_delete=models.CASCADE,
related_name='to_user_id', null=True, blank=True)
action_choices = ((0, '消费'), (1, '充值'), (2, '转账'))
action = models.SmallIntegerField(choices=action_choices, default=0, verbose_name="资金类型",
help_text="0 消费 1 充值 2 转账")
number = models.IntegerField(verbose_name="消耗次数", default=1)
app_id = models.ForeignKey(to="Apps", on_delete=models.CASCADE, verbose_name="属于哪个APP",null=True,blank=True)
udid = models.ForeignKey(to="AppUDID", on_delete=models.CASCADE, verbose_name="所消耗的udid",null=True,blank=True)
developerid = models.ForeignKey(to="AppIOSDeveloperInfo", on_delete=models.CASCADE, verbose_name="所使用苹果开发者账户",null=True,blank=True)
app_info = models.JSONField(max_length=256, verbose_name="属于哪个APP", null=True, blank=True)
udid_info = models.JSONField(max_length=256, verbose_name="设备id信息", null=True, blank=True)
developer_info = models.JSONField(max_length=256, verbose_name="开发者信息", null=True, blank=True)
# app_id = models.ForeignKey(to="Apps", on_delete=models.CASCADE, verbose_name="属于哪个APP",null=True,blank=True)
# udid = models.ForeignKey(to="AppUDID", on_delete=models.CASCADE, verbose_name="所消耗的udid",null=True,blank=True)
# developerid = models.ForeignKey(to="AppIOSDeveloperInfo", on_delete=models.CASCADE, verbose_name="所使用苹果开发者账户",null=True,blank=True)
description = models.CharField(verbose_name="操作描述", max_length=128, default='', blank=True)
created_time = models.DateTimeField(auto_now_add=True, verbose_name="添加时间")
class Meta:
verbose_name = '资金流转账单'
verbose_name_plural = "资金流转账单"
def __str__(self):
return "%s-%s%s" % (self.user_id, self.to_user_id, self.description)
class RemoteClientInfo(models.Model):
remote_addr = models.GenericIPAddressField(verbose_name="远程IP地址")
user_agent = models.CharField(verbose_name="客户端agent", max_length=512)
method = models.CharField(verbose_name="请求方式", max_length=16)
uri_info = models.CharField(verbose_name="访问的URI", max_length=256)
a_domain = models.CharField(verbose_name="前端域名", max_length=128)
description = models.CharField(verbose_name="访问描述", max_length=256)
created_time = models.DateTimeField(auto_now_add=True, verbose_name="访问时间")
class Meta:
verbose_name = '客户端访问记录'
verbose_name_plural = "客户端访问记录"
def __str__(self):
return "%s-%s" % (self.remote_addr, self.description)

@ -22,11 +22,11 @@ from fir_ser.settings import LOGIN, CHANGER, REGISTER
@shared_task
def run_sign_task(format_udid_info, short):
def run_sign_task(format_udid_info, short, client_ip):
app_info = Apps.objects.filter(short=short).first()
with cache.lock("%s_%s_%s" % ('task_sign', app_info.app_id, format_udid_info.get('udid')), timeout=60 * 10):
ios_obj = IosUtils(format_udid_info, app_info.user_id, app_info)
status, msg = ios_obj.sign()
status, msg = ios_obj.sign(client_ip)
if not status:
code = msg.get("code", -1)
if code == 0:

@ -3,11 +3,10 @@
# project: 3月
# author: liuyu
# date: 2020/3/6
from api.utils.app.randomstrings import make_app_uuid
from api.models import AppReleaseInfo, Apps
import random
from api.utils.baseutils import get_user_domain_name
from api.utils.baseutils import make_app_uuid
from api.utils.modelutils import get_user_domain_name
from api.utils.storage.storage import Storage
from api.utils.storage.caches import del_cache_response_by_short
import logging

@ -6,11 +6,10 @@
import datetime
from api.utils.app.shellcmds import shell_command, use_user_pass
from api.utils.baseutils import get_format_time, format_apple_date
from api.utils.baseutils import get_format_time, format_apple_date, make_app_uuid
from fir_ser.settings import SUPER_SIGN_ROOT
import os
import re
from api.utils.app.randomstrings import make_app_uuid
import logging
from api.utils.apple.appleapiv3 import AppStoreConnectApi
import base64

@ -1,27 +0,0 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# project: 3月
# author: liuyu
# date: 2020/3/6
import uuid
def make_from_user_uuid(userinfo):
user_id = userinfo.uid
random_str = uuid.uuid1().__str__().split("-")[0:-1]
user_ran_str = uuid.uuid5(uuid.NAMESPACE_DNS, user_id).__str__().split("-")
user_ran_str.extend(random_str)
new_str = "".join(user_ran_str)
return new_str
def make_app_uuid(userinfo, bundleid):
user_id = userinfo.uid
app_uuid = uuid.uuid5(uuid.NAMESPACE_DNS, "%s" % (user_id + bundleid)).__str__().split("-")
fapp_uuid = "".join(app_uuid)
return fapp_uuid
def make_random_uuid():
random_str = uuid.uuid1().__str__().split("-")
return "".join(random_str)

@ -8,17 +8,17 @@ import uuid, xmltodict, os, logging, time
import zipfile
from api.utils.response import BaseResponse
from fir_ser.settings import SUPER_SIGN_ROOT, MEDIA_ROOT, SERVER_DOMAIN, MOBILE_CONFIG_SIGN_SSL, MSGTEMPLATE
from api.utils.serializer import BillAppInfoSerializer, BillDeveloperInfoSerializer, BillUdidInfoSerializer
from fir_ser.settings import SUPER_SIGN_ROOT, MEDIA_ROOT, MOBILE_CONFIG_SIGN_SSL, MSGTEMPLATE
from api.utils.app.iossignapi import ResignApp, AppDeveloperApiV2
from api.models import APPSuperSignUsedInfo, AppUDID, AppIOSDeveloperInfo, AppReleaseInfo, Apps, APPToDeveloper, \
UDIDsyncDeveloper, DeveloperAppID, DeveloperDevicesID, IosDeveloperPublicPoolBill, UserInfo
from api.utils.app.randomstrings import make_app_uuid, make_from_user_uuid
from api.utils.storage.caches import del_cache_response_by_short, send_msg_over_limit, check_app_permission, \
consume_user_download_times_by_app_obj
from api.utils.utils import delete_app_to_dev_and_file, send_ios_developer_active_status, delete_local_files, \
download_files_form_oss, get_developer_udided
from api.utils.baseutils import file_format_path, delete_app_profile_file, get_profile_full_path, get_user_domain_name, \
get_user_default_domain_name, get_min_default_domain_cname_obj, format_apple_date, get_format_time
from api.utils.baseutils import file_format_path, delete_app_profile_file, get_profile_full_path, format_apple_date, \
get_format_time, make_app_uuid, make_from_user_uuid
from api.utils.storage.storage import Storage
from django.core.cache import cache
from django.db.models import Sum
@ -159,13 +159,6 @@ def make_udid_mobile_config(udid_url, payload_organization, app_name, payload_uu
</plist>'''
def get_post_udid_url(request, short):
server_domain = get_http_server_domain(request)
path_info_lists = [server_domain, "udid", short]
udid_url = "/".join(path_info_lists)
return udid_url
def get_auth_form_developer(developer_obj):
if developer_obj.issuer_id:
auth = {
@ -201,28 +194,14 @@ def err_callback(func, *args, **kwargs):
return wrapper
def get_server_domain_from_request(request, server_domain):
if not server_domain or not server_domain.startswith("http"):
http_host = request.META.get('HTTP_HOST')
server_protocol = request.META.get('SERVER_PROTOCOL')
protocol = 'https'
if server_protocol == 'HTTP/1.1':
protocol = 'http'
server_domain = "%s://%s" % (protocol, http_host)
return server_domain
def get_http_server_domain(request):
server_domain = SERVER_DOMAIN.get('POST_UDID_DOMAIN', None)
return get_server_domain_from_request(request, server_domain)
def get_ios_developer_public_num(user_obj):
ios_developer_base_obj = IosDeveloperPublicPoolBill.objects.filter(user_id=user_obj)
add_number = ios_developer_base_obj.filter(action=1).aggregate(number=Sum('number'))
used_number = ios_developer_base_obj.filter(action=0).aggregate(number=Sum('number'))
add_number = IosDeveloperPublicPoolBill.objects.filter(to_user_id=user_obj, action__in=[1, 2]).aggregate(
number=Sum('number'))
used_number = IosDeveloperPublicPoolBill.objects.filter(user_id=user_obj, action=0).aggregate(number=Sum('number'))
if add_number:
add_number = add_number.get("number", 0)
if not add_number:
return False
used_number = used_number.get("number", 0)
if not used_number:
used_number = 0
@ -231,29 +210,7 @@ def get_ios_developer_public_num(user_obj):
return False
def get_redirect_server_domain(request, user_obj=None, app_domain_name=None):
is_https = False
if user_obj:
if app_domain_name and len(app_domain_name) > 3:
domain_name = app_domain_name
else:
domain_name = get_user_domain_name(user_obj)
if not domain_name:
is_https, domain_name = get_user_default_domain_name(user_obj.default_domain_name)
elif app_domain_name and len(app_domain_name) > 3:
domain_name = app_domain_name
else:
is_https, domain_name = get_user_default_domain_name(get_min_default_domain_cname_obj(True))
protocol = 'http'
if is_https:
protocol = 'https'
server_domain = "%s://%s" % (protocol, domain_name)
return get_server_domain_from_request(request, server_domain)
def get_developer_user_by_app_udid(user_obj,udid):
def get_developer_user_by_app_udid(user_obj, udid):
use_device_obj = APPSuperSignUsedInfo.objects.filter(udid__udid=udid,
user_id=user_obj, developerid__is_actived=True,
developerid__certid__isnull=False).first()
@ -274,24 +231,24 @@ def get_developer_user_by_app_udid(user_obj,udid):
return None
return developer_obj
def get_developer_obj_by_others(user_obj, udid):
result = get_developer_user_by_app_udid(user_obj, udid)
if result:
return result
if not get_ios_developer_public_num(user_obj):
return None
admin_user_obj_list = UserInfo.objects.filter(is_active=True, role=3, is_staff=True).all()
for admin_user_obj in admin_user_obj_list:
result = get_developer_user_by_app_udid(admin_user_obj,udid)
receive_user_obj_list = IosDeveloperPublicPoolBill.objects.filter(to_user_id=user_obj).all()
for receive_user_obj in receive_user_obj_list:
result = get_developer_user_by_app_udid(receive_user_obj.user_id, udid)
if result is None:
continue
else:
logger.warning(f"user admin {admin_user_obj} developer to sign")
logger.warning(f"user receive_user_obj {receive_user_obj.user_id} developer to sign")
return result
return None
class IosUtils(object):
def __init__(self, udid_info, user_obj, app_obj=None):
self.developer_obj = None
@ -468,7 +425,7 @@ class IosUtils(object):
logger.info(f"update sign file end, now upload {storage_obj.storage} {random_file_name}.ipa file")
return storage_obj.upload_file(os.path.join(MEDIA_ROOT, random_file_name + ".ipa"))
def update_developer_used_data(self):
def update_developer_used_data(self, client_ip):
udid_obj = AppUDID.objects.filter(app_id=self.app_obj, udid=self.udid_info.get('udid')).first()
udid_obj.is_download = True
udid_obj.save(update_fields=['is_download'])
@ -476,12 +433,15 @@ class IosUtils(object):
user_id=self.user_obj,
developerid=self.developer_obj,
udid=udid_obj)
IosDeveloperPublicPoolBill.objects.update_or_create(app_id=self.app_obj,
user_id=self.user_obj,
developerid=self.developer_obj,
udid=udid_obj,action=0,number=1)
IosDeveloperPublicPoolBill.objects.update_or_create(user_id=self.user_obj,
app_info=BillAppInfoSerializer(self.app_obj).data,
developer_info=BillDeveloperInfoSerializer(
self.developer_obj).data,
udid_info=BillUdidInfoSerializer(udid_obj).data, action=0,
number=1)
@staticmethod
def update_sign_data(user_obj, app_obj, developer_obj,random_file_name, release_obj,udid):
def update_sign_data(user_obj, app_obj, developer_obj, random_file_name, release_obj, udid):
# 更新新签名的ipa包
if IosUtils.update_sign_file_name(user_obj, app_obj, developer_obj, release_obj,
random_file_name):
@ -502,7 +462,8 @@ class IosUtils(object):
logger.info(f"app_id {app_obj} download profile success. time:{start_time - d_time}")
random_file_name = make_from_user_uuid(developer_obj.user_id)
release_obj = AppReleaseInfo.objects.filter(app_id=app_obj, is_master=True).first()
status, e_result = IosUtils.exec_sign(developer_obj.user_id, app_obj, developer_obj, random_file_name, release_obj)
status, e_result = IosUtils.exec_sign(developer_obj.user_id, app_obj, developer_obj, random_file_name,
release_obj)
if status:
s_time1 = time.time()
logger.info(f"app_id {app_obj} exec sign ipa success. time:{s_time1 - start_time}")
@ -513,7 +474,8 @@ class IosUtils(object):
d_result['msg'] = '数据更新失败,请稍后重试'
return status, d_result
else:
if not IosUtils.update_sign_data(user_obj, app_obj, developer_obj,random_file_name, release_obj,udid):
if not IosUtils.update_sign_data(user_obj, app_obj, developer_obj, random_file_name, release_obj,
udid):
d_result['code'] = 1004
d_result['msg'] = '数据更新失败,请稍后重试'
return status, d_result
@ -532,7 +494,7 @@ class IosUtils(object):
d_result['msg'] = msg
return True, d_result
def sign(self, sign_try_attempts=3):
def sign(self, client_ip, sign_try_attempts=3):
"""
:param sign_try_attempts:
:return: status, result
@ -571,7 +533,8 @@ class IosUtils(object):
with cache.lock("%s_%s_%s" % ('run_sign', self.app_obj.app_id, self.developer_obj.issuer_id),
timeout=60 * 10):
logger.info("start run_sign ...")
return IosUtils.run_sign(self.user_obj, self.app_obj, self.developer_obj, 1, self.udid_info.get('udid'), time.time(),
return IosUtils.run_sign(self.user_obj, self.app_obj, self.developer_obj, 1,
self.udid_info.get('udid'), time.time(),
None)
logger.info("udid %s not exists app_id %s ,need sign" % (self.udid_info.get('udid'), self.app_obj))
@ -629,7 +592,7 @@ class IosUtils(object):
developerid=self.developer_obj,
app_id=self.app_obj)
self.update_developer_used_data()
self.update_developer_used_data(client_ip)
if not self.developer_obj:
d_result['code'] = 1005
@ -638,7 +601,8 @@ class IosUtils(object):
return False, d_result
with cache.lock("%s_%s_%s" % ('run_sign', self.app_obj.app_id, self.developer_obj.issuer_id), timeout=60 * 10):
logger.info("start run_sign ...")
return IosUtils.run_sign(self.user_obj, self.app_obj, self.developer_obj, download_flag, self.udid_info.get('udid'), start_time,
return IosUtils.run_sign(self.user_obj, self.app_obj, self.developer_obj, download_flag,
self.udid_info.get('udid'), start_time,
result)
@staticmethod
@ -689,6 +653,10 @@ class IosUtils(object):
IosUtils.do_disable_device(developer_obj, udid_lists, udid_obj, auth)
SuperSignUsed_obj.delete()
app_udid_obj = UDIDsyncDeveloper.objects.filter(developerid=developer_obj,
udid=udid_obj.udid).first()
DeveloperDevicesID.objects.filter(udid=app_udid_obj, developerid=developer_obj, app_id=app_obj).delete()
@staticmethod
def clean_app_by_user_obj(app_obj):
"""
@ -701,7 +669,7 @@ class IosUtils(object):
for developer_id in developer_id_lists:
developer_obj = AppIOSDeveloperInfo.objects.filter(pk=developer_id[0]).first()
if developer_obj:
if developer_obj and developer_obj.user_id == app_obj.user_id:
IosUtils.clean_app_by_developer_obj(app_obj, developer_obj)
delete_app_to_dev_and_file(developer_obj, app_obj.id)
IosUtils.clean_udid_by_app_obj(app_obj, developer_obj)

@ -6,27 +6,38 @@
import os, re, time
from django.db.models import Count
import datetime
import random
from django.utils import timezone
from fir_ser.settings import SUPER_SIGN_ROOT
from api.models import AppReleaseInfo, UserDomainInfo, DomainCnameInfo, UserAdDisplayInfo
from api.utils.app.randomstrings import make_app_uuid
from fir_ser.settings import SUPER_SIGN_ROOT, SERVER_DOMAIN
from django.core.validators import validate_email
from django.core.exceptions import ValidationError
import logging
from dns.resolver import Resolver
import uuid
logger = logging.getLogger(__name__)
def get_app_d_count_by_app_id(app_id):
d_count = 1
binary_size = AppReleaseInfo.objects.filter(is_master=True, app_id__app_id=app_id).values('binary_size').first()
if binary_size and binary_size.get('binary_size', 0) > 0:
d_count += binary_size.get('binary_size') // 1024 // 1024 // 100
return d_count
def make_from_user_uuid(userinfo):
user_id = userinfo.uid
random_str = uuid.uuid1().__str__().split("-")[0:-1]
user_ran_str = uuid.uuid5(uuid.NAMESPACE_DNS, user_id).__str__().split("-")
user_ran_str.extend(random_str)
new_str = "".join(user_ran_str)
return new_str
def make_app_uuid(userinfo, bundleid):
user_id = userinfo.uid
app_uuid = uuid.uuid5(uuid.NAMESPACE_DNS, "%s" % (user_id + bundleid)).__str__().split("-")
fapp_uuid = "".join(app_uuid)
return fapp_uuid
def make_random_uuid():
random_str = uuid.uuid1().__str__().split("-")
return "".join(random_str)
def file_format_path(user_obj, auth=None):
@ -173,31 +184,32 @@ def get_cname_from_domain(domain):
return str(None)
def get_user_domain_name(obj, domain_type=1):
domain_name = UserDomainInfo.objects.filter(user_id=obj, is_enable=True, app_id=None,
domain_type=domain_type).values_list('domain_name').first()
if domain_name:
return domain_name[0]
return ''
def get_app_domain_name(obj):
domain_name = UserDomainInfo.objects.filter(app_id=obj, is_enable=True, domain_type=2).values_list(
'domain_name').first()
if domain_name:
return domain_name[0]
return ''
def get_user_default_domain_name(domain_cname_obj):
if domain_cname_obj:
return domain_cname_obj.is_https, domain_cname_obj.domain_record
return None, None
def get_min_default_domain_cname_obj(is_system=True):
return min(DomainCnameInfo.objects.annotate(Count('userinfo')).filter(is_enable=True, is_system=is_system),
key=lambda x: x.userinfo__count)
def get_server_domain_from_request(request, server_domain):
if not server_domain or not server_domain.startswith("http"):
http_host = request.META.get('HTTP_HOST')
server_protocol = request.META.get('SERVER_PROTOCOL')
protocol = 'https'
if server_protocol == 'HTTP/1.1':
protocol = 'http'
server_domain = "%s://%s" % (protocol, http_host)
return server_domain
def get_http_server_domain(request):
server_domain = SERVER_DOMAIN.get('POST_UDID_DOMAIN', None)
return get_server_domain_from_request(request, server_domain)
def get_post_udid_url(request, short):
server_domain = get_http_server_domain(request)
path_info_lists = [server_domain, "udid", short]
return "/".join(path_info_lists)
def format_apple_date(s_date):
@ -223,35 +235,6 @@ def check_app_password(app_password, password):
return True
def get_filename_form_file(filename):
file_id_list = filename.split('.')
if file_id_list[-1] in ['ipa', 'apk']:
app_release_obj = AppReleaseInfo.objects.filter(release_id='.'.join(file_id_list[0:-1])).first()
if app_release_obj:
app_obj = app_release_obj.app_id
if app_obj.type == 0:
f_type = '.apk'
else:
f_type = '.ipa'
return f"{app_obj.name}-{app_release_obj.app_version}-{app_obj.short}{f_type}"
return filename
def check_app_domain_name_access(app_obj, access_domain_name, user_obj, extra_domain=None):
if app_obj and access_domain_name:
domain_list = []
if extra_domain:
domain_list.append(extra_domain)
app_domain_name = get_app_domain_name(app_obj)
if app_domain_name: domain_list.append(app_domain_name)
user_domain_name = get_user_domain_name(user_obj)
if user_domain_name: domain_list.append(user_domain_name)
user_qr_domain_name = get_user_domain_name(user_obj, 0)
if user_qr_domain_name: domain_list.append(user_qr_domain_name)
if access_domain_name in domain_list:
return True
def get_real_ip_address(request):
if request.META.get('HTTP_X_FORWARDED_FOR', None):
return request.META.get('HTTP_X_FORWARDED_FOR')
@ -261,21 +244,7 @@ def get_real_ip_address(request):
def get_origin_domain_name(request):
meta = request.META
return meta.get('HTTP_ORIGIN', meta.get('HTTP_REFERER', 'http://xxx/xxx')).split('//')[-1].split('/')[0]
def ad_random_weight(user_obj):
ad_info_list = UserAdDisplayInfo.objects.filter(user_id=user_obj, is_enable=True).order_by('-created_time')
total = sum([ad_info.weight for ad_info in ad_info_list]) # 权重求和
ra = random.uniform(0, total) # 在0与权重和之前获取一个随机数
curr_sum = 0
ret = ad_info_list.first()
for ad_info in ad_info_list:
curr_sum += ad_info.weight # 在遍历中,累加当前权重值
if ra <= curr_sum: # 当随机数<=当前权重和时,返回权重key
ret = ad_info
break
return ret
return request.META.get('HTTP_ORIGIN', meta.get('HTTP_REFERER', 'http://xxx/xxx')).split('//')[-1].split('/')[0]
def format_get_uri(domain, short, data):

@ -0,0 +1,122 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# project: 4月
# author: NinEveN
# date: 2021/4/16
from django.db.models import Count
import random
from api.models import AppReleaseInfo, UserDomainInfo, DomainCnameInfo, UserAdDisplayInfo, RemoteClientInfo
import logging
from urllib.parse import urljoin
from api.utils.baseutils import get_server_domain_from_request, get_user_default_domain_name, get_real_ip_address, \
get_origin_domain_name
logger = logging.getLogger(__name__)
def get_app_d_count_by_app_id(app_id):
d_count = 1
binary_size = AppReleaseInfo.objects.filter(is_master=True, app_id__app_id=app_id).values('binary_size').first()
if binary_size and binary_size.get('binary_size', 0) > 0:
d_count += binary_size.get('binary_size') // 1024 // 1024 // 100
return d_count
def get_user_domain_name(obj, domain_type=1):
domain_name = UserDomainInfo.objects.filter(user_id=obj, is_enable=True, app_id=None,
domain_type=domain_type).values_list('domain_name').first()
if domain_name:
return domain_name[0]
return ''
def get_app_domain_name(obj):
domain_name = UserDomainInfo.objects.filter(app_id=obj, is_enable=True, domain_type=2).values_list(
'domain_name').first()
if domain_name:
return domain_name[0]
return ''
def get_min_default_domain_cname_obj(is_system=True):
return min(DomainCnameInfo.objects.annotate(Count('userinfo')).filter(is_enable=True, is_system=is_system),
key=lambda x: x.userinfo__count)
def get_filename_form_file(filename):
file_id_list = filename.split('.')
if file_id_list[-1] in ['ipa', 'apk']:
app_release_obj = AppReleaseInfo.objects.filter(release_id='.'.join(file_id_list[0:-1])).first()
if app_release_obj:
app_obj = app_release_obj.app_id
if app_obj.type == 0:
f_type = '.apk'
else:
f_type = '.ipa'
return f"{app_obj.name}-{app_release_obj.app_version}-{app_obj.short}{f_type}"
return filename
def ad_random_weight(user_obj):
ad_info_list = UserAdDisplayInfo.objects.filter(user_id=user_obj, is_enable=True).order_by('-created_time')
total = sum([ad_info.weight for ad_info in ad_info_list]) # 权重求和
ra = random.uniform(0, total) # 在0与权重和之前获取一个随机数
curr_sum = 0
ret = ad_info_list.first()
for ad_info in ad_info_list:
curr_sum += ad_info.weight # 在遍历中,累加当前权重值
if ra <= curr_sum: # 当随机数<=当前权重和时,返回权重key
ret = ad_info
break
return ret
def add_remote_info_from_request(request, description):
meta_info = request.META
remote_info = {
'user_agent': meta_info.get('HTTP_USER_AGENT'),
'remote_addr': get_real_ip_address(request),
'method': meta_info.get('REQUEST_METHOD'),
'uri_info': urljoin(meta_info.get('PATH_INFO'), meta_info.get('QUERY_STRING')),
'a_domain': get_origin_domain_name(request),
'description': description
}
RemoteClientInfo.objects.create(**remote_info)
def get_redirect_server_domain(request, user_obj=None, app_domain_name=None):
is_https = False
if user_obj:
if app_domain_name and len(app_domain_name) > 3:
domain_name = app_domain_name
else:
domain_name = get_user_domain_name(user_obj)
if not domain_name:
is_https, domain_name = get_user_default_domain_name(user_obj.default_domain_name)
elif app_domain_name and len(app_domain_name) > 3:
domain_name = app_domain_name
else:
is_https, domain_name = get_user_default_domain_name(get_min_default_domain_cname_obj(True))
protocol = 'http'
if is_https:
protocol = 'https'
server_domain = "%s://%s" % (protocol, domain_name)
return get_server_domain_from_request(request, server_domain)
def check_app_domain_name_access(app_obj, access_domain_name, user_obj, extra_domain=None):
if app_obj and access_domain_name:
domain_list = []
if extra_domain:
domain_list.append(extra_domain)
app_domain_name = get_app_domain_name(app_obj)
if app_domain_name: domain_list.append(app_domain_name)
user_domain_name = get_user_domain_name(user_obj)
if user_domain_name: domain_list.append(user_domain_name)
user_qr_domain_name = get_user_domain_name(user_obj, 0)
if user_qr_domain_name: domain_list.append(user_qr_domain_name)
if access_domain_name in domain_list:
return True

@ -2,8 +2,7 @@ from rest_framework import serializers
from api import models
from api.utils.TokenManager import make_token
from api.utils.app.apputils import bytes2human
from api.utils.app.supersignutils import get_redirect_server_domain
from api.utils.baseutils import get_user_domain_name, get_app_domain_name
from api.utils.modelutils import get_user_domain_name, get_app_domain_name, get_redirect_server_domain
from api.utils.storage.storage import Storage
from api.utils.utils import get_developer_udided, get_choices_dict, get_choices_name_from_key
from api.utils.storage.caches import get_user_free_download_times, get_user_cert_auth_status
@ -467,13 +466,14 @@ class AdminDeveloperSerializer(DeveloperSerializer):
class SuperSignUsedSerializer(serializers.ModelSerializer):
class Meta:
model = models.APPSuperSignUsedInfo
fields = ["created_time", "device_udid", "device_name", "developer_id", "bundle_id", "bundle_name"]
fields = ["created_time", "device_udid", "device_name", "developer_id", "bundle_id", "bundle_name", "other_uid"]
device_udid = serializers.SerializerMethodField()
device_name = serializers.SerializerMethodField()
developer_id = serializers.SerializerMethodField()
bundle_id = serializers.SerializerMethodField()
bundle_name = serializers.SerializerMethodField()
other_uid = serializers.SerializerMethodField()
def get_device_udid(self, obj):
return obj.udid.udid
@ -493,6 +493,15 @@ class SuperSignUsedSerializer(serializers.ModelSerializer):
def get_bundle_name(self, obj):
return obj.app_id.name
def get_other_uid(self, obj):
user_obj = self.context.get('user_obj')
role = 0
if user_obj:
role = user_obj.role
if role == 3:
if obj.user_id != obj.developerid.user_id:
return obj.user_id.uid
class AdminSuperSignUsedSerializer(SuperSignUsedSerializer):
class Meta:
@ -530,6 +539,17 @@ class DeviceUDIDSerializer(serializers.ModelSerializer):
bundle_id = serializers.SerializerMethodField()
bundle_name = serializers.SerializerMethodField()
is_mine = serializers.SerializerMethodField()
other_uid = serializers.SerializerMethodField()
def get_other_uid(self, obj):
user_obj = self.context.get('user_obj')
role = 0
if user_obj:
role = user_obj.role
if role == 3:
super_user_obj = models.APPSuperSignUsedInfo.objects.filter(udid=obj, app_id=obj.app_id).first()
if super_user_obj.developerid.user_id != obj.app_id.user_id:
return obj.app_id.user_id.uid
def get_is_mine(self, obj):
return self.context.get('mine')
@ -682,3 +702,21 @@ class AppAdInfoSerializer(UserAdInfoSerializer):
def get_ad_pic(self, obj):
return get_download_url_from_context(self, obj, '', obj.ad_pic, True)
class BillAppInfoSerializer(serializers.ModelSerializer):
class Meta:
model = models.Apps
fields = ["pk", "app_id", "user_id", "name", "type", "bundle_id", "updated_time"]
class BillDeveloperInfoSerializer(serializers.ModelSerializer):
class Meta:
model = models.AppIOSDeveloperInfo
fields = ["pk", "issuer_id", "user_id", "certid"]
class BillUdidInfoSerializer(serializers.ModelSerializer):
class Meta:
model = models.AppUDID
fields = ["pk", "app_id", "udid", "product", "serial", "version", "imei", "iccid"]

@ -18,7 +18,7 @@ import logging
from oss2 import SizedFileAdapter, determine_part_size
from oss2.models import PartInfo
from api.utils.baseutils import get_filename_form_file
from api.utils.modelutils import get_filename_form_file
logger = logging.getLogger(__name__)

@ -13,7 +13,8 @@ from django.utils import timezone
from fir_ser.settings import CACHE_KEY_TEMPLATE, SERVER_DOMAIN, SYNC_CACHE_TO_DATABASE, DEFAULT_MOBILEPROVISION, \
USER_FREE_DOWNLOAD_TIMES, AUTH_USER_FREE_DOWNLOAD_TIMES
from api.utils.storage.storage import Storage, LocalStorage
from api.utils.baseutils import get_app_d_count_by_app_id, get_app_domain_name, check_app_password, get_user_domain_name
from api.utils.modelutils import get_app_d_count_by_app_id, get_app_domain_name, get_user_domain_name
from api.utils.baseutils import check_app_password
import logging
from django.db.models import F

@ -5,10 +5,11 @@
# date: 2020/5/7
import os, datetime, random
import binascii
from api.utils.modelutils import get_app_d_count_by_app_id
from fir_ser.settings import SERVER_DOMAIN, CAPTCHA_LENGTH, MEDIA_ROOT, CACHE_KEY_TEMPLATE
from api.models import APPSuperSignUsedInfo, APPToDeveloper, \
UDIDsyncDeveloper, UserInfo, AppReleaseInfo, AppScreenShot, Token, DeveloperDevicesID, UserAdDisplayInfo
from api.utils.storage.caches import get_app_d_count_by_app_id
from api.utils.storage.localApi import LocalStorage
from api.utils.storage.storage import Storage
from api.utils.tempcaches import TmpCache

@ -19,7 +19,7 @@ from api.utils.serializer import AppsSerializer, AppReleaseSerializer, AppsListS
from rest_framework.pagination import PageNumberPagination
import logging
from api.utils.utils import delete_local_files, delete_app_screenshots_files
from api.utils.baseutils import get_user_domain_name, get_app_domain_name
from api.utils.modelutils import get_user_domain_name, get_app_domain_name
from api.base_views import app_delete
logger = logging.getLogger(__name__)
@ -113,7 +113,7 @@ class AppInfoView(APIView):
if app_obj:
app_serializer = AppsSerializer(app_obj, context={"storage": Storage(request.user)})
res.data = app_serializer.data
count = APPToDeveloper.objects.filter(app_id=app_obj).count()
count = APPToDeveloper.objects.filter(app_id=app_obj, developerid__user_id=request.user).count()
res.data["count"] = count
else:
logger.error(f"app_id:{app_id} is not found in user:{request.user}")
@ -226,7 +226,7 @@ class AppInfoView(APIView):
if developer_count == 0 and not get_ios_developer_public_num(request.user):
logger.error(f"app_id:{app_id} can't open super_sign,owner has no ios developer")
res.code = 1008
res.msg = "超级签开发者不存在,无法开启"
res.msg = "超级签余额不足,无法开启"
return Response(res.dict)
app_obj.issupersign = data.get("issupersign", app_obj.issupersign)
update_fields.append("issupersign")

@ -6,8 +6,8 @@
from rest_framework.pagination import PageNumberPagination
from rest_framework.views import APIView
from api.utils.baseutils import is_valid_domain, get_cname_from_domain, get_user_domain_name, \
get_min_default_domain_cname_obj
from api.utils.baseutils import is_valid_domain, get_cname_from_domain
from api.utils.modelutils import get_user_domain_name, get_min_default_domain_cname_obj
from api.utils.response import BaseResponse
from api.utils.auth import ExpiringTokenAuthentication, DownloadQrPermission
from rest_framework.response import Response
@ -15,7 +15,7 @@ from api.models import UserDomainInfo, Apps
import logging
from api.utils.serializer import DomainNameSerializer
from api.utils.storage.caches import del_cache_response_by_short, reset_app_wx_easy_type, reset_short_response_cache
from api.utils.storage.caches import del_cache_response_by_short, reset_app_wx_easy_type
from api.utils.utils import get_choices_dict
logger = logging.getLogger(__name__)

@ -10,9 +10,8 @@ from api.utils.TokenManager import verify_token
from api.utils.response import BaseResponse
from rest_framework.response import Response
from fir_ser import settings
from api.utils.app.randomstrings import make_random_uuid
from api.utils.app.apputils import make_resigned
from api.utils.app.supersignutils import make_sign_udid_mobile_config, get_post_udid_url, get_redirect_server_domain
from api.utils.app.supersignutils import make_sign_udid_mobile_config
from api.utils.storage.storage import Storage, get_local_storage
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, consume_user_download_times, check_app_permission
@ -22,9 +21,11 @@ from api.utils.serializer import AppsShortSerializer, AppAdInfoSerializer
from api.models import Apps, AppReleaseInfo, APPToDeveloper, APPSuperSignUsedInfo
from django.http import FileResponse
import logging
from api.utils.baseutils import get_profile_full_path, get_app_domain_name, get_filename_form_file, \
check_app_domain_name_access, get_real_ip_address, get_origin_domain_name, ad_random_weight, format_get_uri
from api.utils.baseutils import get_profile_full_path, make_random_uuid, get_real_ip_address, get_origin_domain_name, \
format_get_uri, get_post_udid_url
from api.utils.throttle import VisitShortThrottle, InstallShortThrottle, InstallThrottle1, InstallThrottle2
from api.utils.modelutils import get_app_domain_name, get_filename_form_file, check_app_domain_name_access, \
ad_random_weight, get_redirect_server_domain
logger = logging.getLogger(__name__)

@ -10,7 +10,8 @@ from rest_framework.views import APIView
from api.utils.utils import get_captcha, valid_captcha, \
get_sender_sms_token, is_valid_sender_code, get_sender_email_token, get_random_username, \
check_username_exists, set_user_token
from api.utils.baseutils import is_valid_phone, is_valid_email, get_min_default_domain_cname_obj, get_real_ip_address
from api.utils.baseutils import is_valid_phone, is_valid_email, get_real_ip_address
from api.utils.modelutils import get_min_default_domain_cname_obj
from api.utils.auth import ExpiringTokenAuthentication
from api.utils.response import BaseResponse
from fir_ser.settings import REGISTER, LOGIN, CHANGER

@ -3,9 +3,8 @@
# project: 3月
# author: liuyu
# date: 2020/3/6
from api.utils.app.randomstrings import make_random_uuid
from api.utils.app.supersignutils import udid_bytes_to_dict, get_redirect_server_domain, make_sign_udid_mobile_config, \
get_post_udid_url, get_http_server_domain, get_server_domain_from_request
from api.utils.app.supersignutils import udid_bytes_to_dict, make_sign_udid_mobile_config, IosUtils
from api.models import Apps
from django.views import View
from django.http import HttpResponsePermanentRedirect, FileResponse, HttpResponse
@ -18,7 +17,8 @@ from fir_ser.celery import app
import logging
from rest_framework.views import APIView
from api.utils.baseutils import get_app_domain_name
from api.utils.baseutils import get_real_ip_address, get_http_server_domain, make_random_uuid
from api.utils.modelutils import get_app_domain_name, get_redirect_server_domain
from celery.exceptions import TimeoutError
logger = logging.getLogger(__name__)
@ -41,7 +41,9 @@ class IosUDIDView(View):
if res.code != 1000:
msg = "&msg=%s" % res.msg
else:
c_task = run_sign_task.apply_async((format_udid_info, short))
client_ip = get_real_ip_address(request)
logger.info(f"client_ip {client_ip} short {short} app_info {app_info}")
c_task = run_sign_task.apply_async((format_udid_info, short, client_ip))
task_id = c_task.id
logger.info(f"sign app {app_info} task_id:{task_id}")
try:

@ -190,11 +190,11 @@ def base_super_sign_used_info(request):
udid = request.query_params.get("udid", None)
bundle_id = request.query_params.get("bundleid", None)
developer_id = request.query_params.get("appid", None)
mine = False
super_sign_used_objs = APPSuperSignUsedInfo.objects.filter(user_id=request.user, )
mine = True
super_sign_used_objs = APPSuperSignUsedInfo.objects.filter(developerid__user_id=request.user, )
if not super_sign_used_objs:
super_sign_used_objs = APPSuperSignUsedInfo.objects.filter(developerid__user_id=request.user, )
mine = True
super_sign_used_objs = APPSuperSignUsedInfo.objects.filter(user_id=request.user, )
mine = False
if developer_id:
super_sign_used_objs = super_sign_used_objs.filter(developerid__issuer_id=developer_id)
if udid:
@ -215,7 +215,8 @@ class SuperSignUsedView(APIView):
app_page_serializer = page_obj.paginate_queryset(queryset=super_sign_used_objs.order_by("-created_time"),
request=request,
view=self)
app_serializer = SuperSignUsedSerializer(app_page_serializer, many=True, context={'mine': mine})
app_serializer = SuperSignUsedSerializer(app_page_serializer, many=True,
context={'mine': mine, 'user_obj': request.user})
res.data = app_serializer.data
res.count = super_sign_used_objs.count()
return Response(res.dict)
@ -228,12 +229,13 @@ class AppUDIDUsedView(APIView):
def get(self, request):
res = BaseResponse()
super_sign_used_objs, mine = base_super_sign_used_info(request)
app_udid_objs = AppUDID.objects.filter(app_id__appsupersignusedinfo__in=super_sign_used_objs)
app_udid_objs = AppUDID.objects.filter(app_id__appsupersignusedinfo__in=super_sign_used_objs).distinct()
page_obj = PageNumber()
app_page_serializer = page_obj.paginate_queryset(queryset=app_udid_objs.order_by("-created_time"),
request=request,
view=self)
app_serializer = DeviceUDIDSerializer(app_page_serializer, many=True, context={'mine': mine} )
app_serializer = DeviceUDIDSerializer(app_page_serializer, many=True,
context={'mine': mine, 'user_obj': request.user})
res.data = app_serializer.data
res.count = app_udid_objs.count()
return Response(res.dict)

@ -5,18 +5,16 @@
# date: 2020/3/6
from api.utils.TokenManager import verify_token
from api.utils.app.apputils import get_random_short, save_app_infos
from api.utils.baseutils import get_app_domain_name
from api.utils.modelutils import get_app_domain_name, get_redirect_server_domain
from api.utils.storage.storage import Storage
from api.utils.storage.caches import upload_file_tmp_name, del_cache_response_by_short
from api.models import Apps, AppReleaseInfo, UserInfo, AppScreenShot, CertificationInfo, UserAdDisplayInfo
from api.utils.app.randomstrings import make_app_uuid
from api.utils.baseutils import make_app_uuid, make_from_user_uuid
from rest_framework.views import APIView
from api.utils.response import BaseResponse
from api.utils.auth import ExpiringTokenAuthentication
from api.utils.app.randomstrings import make_from_user_uuid
from rest_framework.response import Response
from fir_ser import settings
from api.utils.app.supersignutils import get_redirect_server_domain
from api.tasks import run_resign_task
import os, json, logging

@ -332,7 +332,7 @@ class AppInfo(object):
def check_depends():
cmd_list = ['--upgrade pip', 'setuptools-rust', 'oss2', 'requests-toolbelt', 'androguard', 'qiniu','requests']
cmd_list = ['--upgrade pip', 'setuptools-rust', 'oss2', 'requests-toolbelt', 'androguard', 'qiniu', 'requests']
for cmd in cmd_list:
os.system('pip install %s' % cmd)

Loading…
Cancel
Save