签名账户设备转移功能

dependabot/npm_and_yarn/fir_admin/url-parse-1.5.10
nineven 3 years ago
parent adc71de160
commit f5ffc3632f
  1. 1
      fir_admin/.env.development
  2. 68
      fir_client/src/components/user/FirSuperSignBase.vue
  3. 2
      fir_ser/admin/utils/exception.py
  4. 5
      fir_ser/api/utils/modelutils.py
  5. 37
      fir_ser/api/utils/serializer.py
  6. 42
      fir_ser/api/views/supersign.py
  7. 12
      fir_ser/common/base/baseutils.py
  8. 1
      fir_ser/fir_ser/settings.py

@ -3,3 +3,4 @@ ENV = 'development'
# base api # base api
VUE_APP_BASE_API = 'https://flyapps.cn/api/v3/fir/server' VUE_APP_BASE_API = 'https://flyapps.cn/api/v3/fir/server'
#VUE_APP_BASE_API = 'https://app.hehelucky.cn/api/v3/fir/server'

@ -777,21 +777,29 @@
width="200"> width="200">
<template slot-scope="scope"> <template slot-scope="scope">
<el-popover placement="top" trigger="hover"> <el-popover placement="top" trigger="hover">
<p>开发者ID: {{ scope.row.developer_id }}</p> <p>开发者ID: {{ get_developer_uid(scope.row.developer_id) }}</p>
<p>开发者备注: {{ scope.row.developer_description }}</p> <p>开发者备注: {{ scope.row.developer_description }}</p>
<p>开发者状态: {{ scope.row.developer_status }}</p> <p>开发者状态: {{ scope.row.developer_status }}</p>
<div slot="reference" class="name-wrapper"> <div slot="reference" class="name-wrapper">
<span>{{ scope.row.developer_id }}</span> <span>{{ get_developer_uid(scope.row.developer_id) }}</span>
</div>
</el-popover>
</template>
</el-table-column>
<el-table-column
align="center"
label="已经分配其他用户"
prop="other_uid">
<template slot-scope="scope">
<el-popover v-if="scope.row.other_uid" placement="top" trigger="hover">
<p>分配用户uid: {{ scope.row.other_uid.uid }}</p>
<p>分配用户昵称: {{ scope.row.other_uid.name }}</p>
<div slot="reference" class="name-wrapper">
<span>{{ scope.row.other_uid.uid }}</span>
</div> </div>
</el-popover> </el-popover>
</template> </template>
</el-table-column> </el-table-column>
<!-- <el-table-column-->
<!-- v-if="$store.state.userinfo&&$store.state.userinfo.role === 3"-->
<!-- align="center"-->
<!-- label="被使用户uid"-->
<!-- prop="other_uid">-->
<!-- </el-table-column>-->
<el-table-column <el-table-column
:formatter="deviceformatter" :formatter="deviceformatter"
align="center" align="center"
@ -885,21 +893,29 @@
prop="issuer_id"> prop="issuer_id">
<template slot-scope="scope"> <template slot-scope="scope">
<el-popover placement="top" trigger="hover"> <el-popover placement="top" trigger="hover">
<p>开发者ID: {{ scope.row.issuer_id }}</p> <p>开发者ID: {{ get_developer_uid(scope.row.issuer_id) }}</p>
<p>开发者备注: {{ scope.row.developer_description }}</p> <p>开发者备注: {{ scope.row.developer_description }}</p>
<p>开发者状态: {{ scope.row.developer_status }}</p> <p>开发者状态: {{ scope.row.developer_status }}</p>
<div slot="reference" class="name-wrapper"> <div slot="reference" class="name-wrapper">
<span>{{ scope.row.issuer_id }}</span> <span>{{ get_developer_uid(scope.row.issuer_id) }}</span>
</div>
</el-popover>
</template>
</el-table-column>
<el-table-column
align="center"
label="已经分配其他用户"
prop="other_uid">
<template slot-scope="scope">
<el-popover v-if="scope.row.other_uid" placement="top" trigger="hover">
<p>分配用户uid: {{ scope.row.other_uid.uid }}</p>
<p>分配用户昵称: {{ scope.row.other_uid.name }}</p>
<div slot="reference" class="name-wrapper">
<span>{{ scope.row.other_uid.uid }}</span>
</div> </div>
</el-popover> </el-popover>
</template> </template>
</el-table-column> </el-table-column>
<!-- <el-table-column-->
<!-- v-if="$store.state.userinfo&&$store.state.userinfo.role === 3"-->
<!-- align="center"-->
<!-- label="被使用户uid"-->
<!-- prop="other_uid">-->
<!-- </el-table-column>-->
<el-table-column <el-table-column
:formatter="deviceformatter" :formatter="deviceformatter"
align="center" align="center"
@ -922,7 +938,7 @@
</el-button> </el-button>
</el-tooltip> </el-tooltip>
</div> </div>
<div style="margin-top: 5px"> <div v-if="!(scope.row.issuer_id && scope.row.issuer_id.indexOf(':')> -1)" style="margin-top: 5px">
<el-tooltip content="删除的同时,会检测并同时禁用苹果开发者设备" placement="bottom"> <el-tooltip content="删除的同时,会检测并同时禁用苹果开发者设备" placement="bottom">
<el-button <el-button
size="mini" size="mini"
@ -1212,6 +1228,12 @@ export default {
} }
}, },
methods: { methods: {
get_developer_uid(uid) {
if (uid && uid.indexOf(':') > -1) {
return '公共账号池'
} else
return uid
},
changeDevice(info, disabled) { changeDevice(info, disabled) {
this.iosudevicesFun("PUT", {developer_id: info.developer_id, udid: info.udid, disabled: disabled}) this.iosudevicesFun("PUT", {developer_id: info.developer_id, udid: info.udid, disabled: disabled})
}, },
@ -1403,7 +1425,17 @@ export default {
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}).then(() => { }).then(() => {
this.iosdevicesudidFun('DELETE', {id: scope.row.id, aid: scope.row.app_id, disabled: disabled}, scope); let other_uid = scope.row.other_uid
let uid = ''
if (other_uid && other_uid.uid) {
uid = other_uid.uid
}
this.iosdevicesudidFun('DELETE', {
id: scope.row.id,
aid: scope.row.app_id,
disabled: disabled,
uid: uid
}, scope);
}).catch(() => { }).catch(() => {
this.$message({ this.$message({
type: 'info', type: 'info',

@ -20,4 +20,4 @@ def common_exception_handler(exc, context):
if not ret: # drf内置处理不了,丢给django 的,我们自己来处理 if not ret: # drf内置处理不了,丢给django 的,我们自己来处理
return ApiResponse(msg='error', result=str(exc)) return ApiResponse(msg='error', result=str(exc))
else: else:
return ApiResponse(msg='error', data=ret.data) return ApiResponse(msg='error', status=ret.status_code, **ret.data, )

@ -258,6 +258,11 @@ def update_or_create_developer_udid_info(device_obj, developer_obj):
return UDIDsyncDeveloper.objects.update_or_create(developerid=developer_obj, udid=device_obj.udid, defaults=device) return UDIDsyncDeveloper.objects.update_or_create(developerid=developer_obj, udid=device_obj.udid, defaults=device)
def check_uid_has_relevant(user_uid, to_user_uid):
if user_uid and to_user_uid:
return IosDeveloperPublicPoolBill.objects.filter(user_id__uid=user_uid, to_user_id__uid=to_user_uid).first()
class PageNumber(PageNumberPagination): class PageNumber(PageNumberPagination):
page_size = 10 # 每页显示多少条 page_size = 10 # 每页显示多少条
page_size_query_param = 'size' # URL中每页显示条数的参数 page_size_query_param = 'size' # URL中每页显示条数的参数

@ -11,9 +11,9 @@ from api.utils.modelutils import get_user_domain_name, get_app_domain_name, get_
from api.utils.storage.caches import get_user_free_download_times, get_user_cert_auth_status from api.utils.storage.caches import get_user_free_download_times, get_user_cert_auth_status
from api.utils.storage.storage import Storage from api.utils.storage.storage import Storage
from api.utils.utils import get_developer_udided from api.utils.utils import get_developer_udided
from common.base.baseutils import get_choices_dict, get_choices_name_from_key from common.base.baseutils import get_choices_dict, get_choices_name_from_key, AppleDeveloperUid
from common.cache.storage import AdPicShowCache from common.cache.storage import AdPicShowCache
from fir_ser.settings import DEVELOPER_USE_STATUS from fir_ser.settings import DEVELOPER_USE_STATUS, DEVELOPER_UID_KEY
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -470,16 +470,14 @@ class SuperSignUsedSerializer(serializers.ModelSerializer):
developer_status = serializers.SerializerMethodField() developer_status = serializers.SerializerMethodField()
def get_developer_status(self, obj): def get_developer_status(self, obj):
if self.context.get('mine'):
return obj.developerid.get_status_display() return obj.developerid.get_status_display()
else:
return '公共账号池'
def get_developer_id(self, obj): def get_developer_id(self, obj):
issuer_id = obj.developerid.issuer_id
if self.context.get('mine'): if self.context.get('mine'):
return obj.developerid.issuer_id return issuer_id
else: else:
return '公共账号池' return f"{DEVELOPER_UID_KEY}{AppleDeveloperUid().get_encrypt_uid(issuer_id)}"
def get_developer_description(self, obj): def get_developer_description(self, obj):
if self.context.get('mine'): if self.context.get('mine'):
@ -489,12 +487,9 @@ class SuperSignUsedSerializer(serializers.ModelSerializer):
def get_other_uid(self, obj): def get_other_uid(self, obj):
user_obj = self.context.get('user_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: if obj.user_id != obj.developerid.user_id:
return obj.user_id.uid if user_obj.uid != obj.user_id.uid:
return {'uid': obj.user_id.uid, 'name': obj.user_id.first_name}
class DeveloperDeviceSerializer(serializers.ModelSerializer): class DeveloperDeviceSerializer(serializers.ModelSerializer):
@ -529,16 +524,14 @@ class DeviceUDIDSerializer(serializers.ModelSerializer):
other_uid = serializers.SerializerMethodField() other_uid = serializers.SerializerMethodField()
def get_issuer_id(self, obj): def get_issuer_id(self, obj):
issuer_id = obj.udid.developerid.issuer_id
if self.context.get('mine'): if self.context.get('mine'):
return obj.udid.developerid.issuer_id return issuer_id
else: else:
return '公共账号池' return f"{DEVELOPER_UID_KEY}{AppleDeveloperUid().get_encrypt_uid(issuer_id)}"
def get_developer_status(self, obj): def get_developer_status(self, obj):
if self.context.get('mine'):
return obj.udid.developerid.get_status_display() return obj.udid.developerid.get_status_display()
else:
return '公共账号池'
def get_developer_description(self, obj): def get_developer_description(self, obj):
if self.context.get('mine'): if self.context.get('mine'):
@ -548,13 +541,11 @@ class DeviceUDIDSerializer(serializers.ModelSerializer):
def get_other_uid(self, obj): def get_other_uid(self, obj):
user_obj = self.context.get('user_obj') user_obj = self.context.get('user_obj')
role = 0 user_obj_new = obj.app_id.user_id
if user_obj: if user_obj.pk != user_obj_new.pk:
role = user_obj.role
if role == 3:
super_user_obj = models.APPSuperSignUsedInfo.objects.filter(udid=obj, app_id=obj.app_id).first() 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: if super_user_obj.developerid.user_id != user_obj_new:
return obj.app_id.user_id.uid return {'uid': user_obj_new.uid, 'name': user_obj_new.first_name}
def get_is_mine(self, obj): def get_is_mine(self, obj):
return self.context.get('mine') return self.context.get('mine')

@ -16,15 +16,16 @@ from api.models import AppIOSDeveloperInfo, APPSuperSignUsedInfo, AppUDID, IosDe
UDIDsyncDeveloper, AppleDeveloperToAppUse, Apps, DeveloperAppID, APPToDeveloper, DeveloperDevicesID UDIDsyncDeveloper, AppleDeveloperToAppUse, Apps, DeveloperAppID, APPToDeveloper, DeveloperDevicesID
from api.utils.app.supersignutils import IosUtils from api.utils.app.supersignutils import IosUtils
from api.utils.auth import ExpiringTokenAuthentication, SuperSignPermission from api.utils.auth import ExpiringTokenAuthentication, SuperSignPermission
from api.utils.modelutils import get_user_public_used_sign_num, get_user_public_sign_num, PageNumber from api.utils.modelutils import get_user_public_used_sign_num, get_user_public_sign_num, PageNumber, \
check_uid_has_relevant
from api.utils.response import BaseResponse from api.utils.response import BaseResponse
from api.utils.serializer import DeveloperSerializer, SuperSignUsedSerializer, DeviceUDIDSerializer, BillInfoSerializer, \ from api.utils.serializer import DeveloperSerializer, SuperSignUsedSerializer, DeviceUDIDSerializer, BillInfoSerializer, \
DeveloperDeviceSerializer, AppleDeveloperToAppUseSerializer, AppleDeveloperToAppUseAppsSerializer DeveloperDeviceSerializer, AppleDeveloperToAppUseSerializer, AppleDeveloperToAppUseAppsSerializer
from api.utils.storage.caches import get_app_download_url from api.utils.storage.caches import get_app_download_url
from api.utils.utils import get_developer_devices from api.utils.utils import get_developer_devices
from common.base.baseutils import get_choices_dict, get_choices_name_from_key from common.base.baseutils import get_choices_dict, get_choices_name_from_key, AppleDeveloperUid
from common.cache.state import CleanSignDataState from common.cache.state import CleanSignDataState
from fir_ser.settings import DEVELOPER_USE_STATUS, DEVELOPER_DISABLED_STATUS from fir_ser.settings import DEVELOPER_USE_STATUS, DEVELOPER_DISABLED_STATUS, DEVELOPER_UID_KEY
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -315,8 +316,17 @@ class SuperSignUsedView(APIView):
device_udid = data.get('device_udid', '') device_udid = data.get('device_udid', '')
developer_id = data.get('developer_id', '') developer_id = data.get('developer_id', '')
bundle_id = data.get('bundle_id', '') bundle_id = data.get('bundle_id', '')
other_uid_info = data.get('other_uid', '')
if device_udid and developer_id and bundle_id: if device_udid and developer_id and bundle_id:
app_obj = Apps.objects.filter(user_id=request.user, bundle_id=bundle_id).first() app_obj = Apps.objects.filter(user_id=request.user, bundle_id=bundle_id).first()
if app_obj is None and not developer_id.startswith(DEVELOPER_UID_KEY):
if other_uid_info:
other_uid = other_uid_info.get('uid')
if other_uid and check_uid_has_relevant(request.user.uid, other_uid):
app_obj = Apps.objects.filter(bundle_id=bundle_id).first()
if developer_id.startswith(DEVELOPER_UID_KEY):
developer_id = AppleDeveloperUid().get_decrypt_uid(developer_id.lstrip('T:'))
app_to_dev_obj = APPToDeveloper.objects.filter(app_id=app_obj, developerid__issuer_id=developer_id).first() app_to_dev_obj = APPToDeveloper.objects.filter(app_id=app_obj, developerid__issuer_id=developer_id).first()
if app_obj and app_to_dev_obj: if app_obj and app_to_dev_obj:
res = get_app_download_url(request, res, app_obj.app_id, app_obj.short, app_obj.password, res = get_app_download_url(request, res, app_obj.app_id, app_obj.short, app_obj.password,
@ -346,6 +356,7 @@ class AppUDIDUsedView(APIView):
def delete(self, request): def delete(self, request):
res = BaseResponse() res = BaseResponse()
pk = request.query_params.get("id", None) pk = request.query_params.get("id", None)
other_uid = request.query_params.get("uid", None)
app_id = request.query_params.get("aid", None) app_id = request.query_params.get("aid", None)
disabled = request.query_params.get("disabled", None) disabled = request.query_params.get("disabled", None)
if disabled is not None and disabled == '1': if disabled is not None and disabled == '1':
@ -353,15 +364,22 @@ class AppUDIDUsedView(APIView):
else: else:
disabled = False disabled = False
app_udid_obj = AppUDID.objects.filter(pk=pk, app_id__user_id=request.user) app_udid_obj = AppUDID.objects.filter(pk=pk, app_id__user_id=request.user)
if not app_udid_obj and check_uid_has_relevant(request.user.uid, other_uid):
app_udid_obj = AppUDID.objects.filter(pk=pk, app_id__user_id__uid=other_uid)
if app_udid_obj: if app_udid_obj:
super_sign_used_obj = APPSuperSignUsedInfo.objects.filter(udid=app_udid_obj.first()).first() super_sign_used_obj = APPSuperSignUsedInfo.objects.filter(udid=app_udid_obj.first()).first()
if super_sign_used_obj and super_sign_used_obj.developerid.user_id.pk == request.user.pk: if super_sign_used_obj:
if super_sign_used_obj.developerid.user_id.pk == request.user.pk:
logger.error(f"user {request.user} delete devices {app_udid_obj}") logger.error(f"user {request.user} delete devices {app_udid_obj}")
IosUtils.disable_udid(app_udid_obj.first(), app_id, disabled) IosUtils.disable_udid(app_udid_obj.first(), app_id, disabled)
else:
IosUtils.disable_udid(app_udid_obj.first(), app_id)
# res.code = 10002
# res.msg = '公共账号池不允许禁用删除'
app_udid_obj.delete() app_udid_obj.delete()
else: else:
res.code = 10002 res.code = 10003
res.msg = '公共账号池不允许删除' res.msg = '数据异常,删除失败'
return Response(res.dict) return Response(res.dict)
@ -468,8 +486,12 @@ class DeviceUsedBillView(APIView):
res = BaseResponse() res = BaseResponse()
udid = request.query_params.get("udid", None) udid = request.query_params.get("udid", None)
act = request.query_params.get("act", None) act = request.query_params.get("act", None)
receive_user_id_list = IosDeveloperPublicPoolBill.objects.filter(user_id=request.user,
to_user_id__isnull=False).values(
'to_user_id').distinct()
user_used_list = IosDeveloperPublicPoolBill.objects.filter( user_used_list = IosDeveloperPublicPoolBill.objects.filter(
Q(to_user_id=request.user) | Q(user_id=request.user)) Q(to_user_id=request.user) | Q(user_id=request.user) | Q(user_id_id__in=receive_user_id_list))
page_obj = PageNumber() page_obj = PageNumber()
if udid: if udid:
user_used_list = user_used_list.filter(udid=udid) user_used_list = user_used_list.filter(udid=udid)
@ -512,7 +534,11 @@ class DeviceUsedRankInfoView(APIView):
search_key = request.query_params.get("appnamesearch") search_key = request.query_params.get("appnamesearch")
start_time = request.query_params.get("start_time") start_time = request.query_params.get("start_time")
end_time = request.query_params.get("end_time") end_time = request.query_params.get("end_time")
app_used_sign_objs = APPSuperSignUsedInfo.objects.filter(user_id=request.user) receive_user_id_list = IosDeveloperPublicPoolBill.objects.filter(user_id=request.user,
to_user_id__isnull=False).values(
'to_user_id').distinct()
app_used_sign_objs = APPSuperSignUsedInfo.objects.filter(
Q(user_id=request.user) | Q(user_id_id__in=receive_user_id_list))
if search_key: if search_key:
app_used_sign_objs = app_used_sign_objs.filter( app_used_sign_objs = app_used_sign_objs.filter(
Q(app_id__name=search_key) | Q(app_id__bundle_id=search_key) | Q( Q(app_id__name=search_key) | Q(app_id__bundle_id=search_key) | Q(

@ -56,6 +56,18 @@ class AESCipher(object):
return data return data
class AppleDeveloperUid(object):
def __init__(self):
self.cipher = AESCipher(self.__class__.__name__)
def get_encrypt_uid(self, raw):
return self.cipher.encrypt(raw.encode('utf-8')).decode('utf-8')
def get_decrypt_uid(self, enc):
return self.cipher.decrypt(enc)
def make_from_user_uuid(uid): def make_from_user_uuid(uid):
random_str = uuid.uuid1().__str__().split("-")[0:-1] random_str = uuid.uuid1().__str__().split("-")[0:-1]
user_ran_str = uuid.uuid5(uuid.NAMESPACE_DNS, uid).__str__().split("-") user_ran_str = uuid.uuid5(uuid.NAMESPACE_DNS, uid).__str__().split("-")

@ -280,6 +280,7 @@ CACHE_KEY_TEMPLATE = {
DATA_DOWNLOAD_KEY = "d_token" DATA_DOWNLOAD_KEY = "d_token"
FILE_UPLOAD_TMP_KEY = ".tmp" FILE_UPLOAD_TMP_KEY = ".tmp"
DEVELOPER_UID_KEY = "T:"
USER_FREE_DOWNLOAD_TIMES = 5 USER_FREE_DOWNLOAD_TIMES = 5
AUTH_USER_FREE_DOWNLOAD_TIMES = 10 AUTH_USER_FREE_DOWNLOAD_TIMES = 10
NEW_USER_GIVE_DOWNLOAD_TIMES = 100 NEW_USER_GIVE_DOWNLOAD_TIMES = 100

Loading…
Cancel
Save