parent
8de6e4a87d
commit
789b9a0c58
@ -0,0 +1,18 @@ |
|||||||
|
# Generated by Django 3.0.3 on 2020-04-15 19:22 |
||||||
|
|
||||||
|
from django.db import migrations, models |
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration): |
||||||
|
|
||||||
|
dependencies = [ |
||||||
|
('api', '0026_auto_20200414_1505'), |
||||||
|
] |
||||||
|
|
||||||
|
operations = [ |
||||||
|
migrations.AddField( |
||||||
|
model_name='apps', |
||||||
|
name='issupersign', |
||||||
|
field=models.BigIntegerField(default=False, verbose_name='是否超级签名包'), |
||||||
|
), |
||||||
|
] |
@ -0,0 +1,31 @@ |
|||||||
|
# Generated by Django 3.0.3 on 2020-04-16 08:33 |
||||||
|
|
||||||
|
from django.db import migrations, models |
||||||
|
import django.db.models.deletion |
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration): |
||||||
|
|
||||||
|
dependencies = [ |
||||||
|
('api', '0027_apps_issupersign'), |
||||||
|
] |
||||||
|
|
||||||
|
operations = [ |
||||||
|
migrations.CreateModel( |
||||||
|
name='AppUDID', |
||||||
|
fields=[ |
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
||||||
|
('udid', models.CharField(db_index=True, max_length=64, unique=True, verbose_name='udid唯一标识')), |
||||||
|
('product', models.CharField(db_index=True, max_length=64, verbose_name='产品')), |
||||||
|
('serial', models.CharField(db_index=True, max_length=64, verbose_name='序列号')), |
||||||
|
('version', models.CharField(db_index=True, max_length=64, verbose_name='型号')), |
||||||
|
('created_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), |
||||||
|
('app_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.Apps', verbose_name='属于哪个APP')), |
||||||
|
], |
||||||
|
options={ |
||||||
|
'verbose_name': '应用详情', |
||||||
|
'verbose_name_plural': '应用详情', |
||||||
|
'unique_together': {('app_id', 'udid')}, |
||||||
|
}, |
||||||
|
), |
||||||
|
] |
@ -0,0 +1,38 @@ |
|||||||
|
# Generated by Django 3.0.3 on 2020-04-16 09:15 |
||||||
|
|
||||||
|
from django.db import migrations, models |
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration): |
||||||
|
|
||||||
|
dependencies = [ |
||||||
|
('api', '0028_appudid'), |
||||||
|
] |
||||||
|
|
||||||
|
operations = [ |
||||||
|
migrations.AddField( |
||||||
|
model_name='appudid', |
||||||
|
name='iccid', |
||||||
|
field=models.CharField(blank=True, max_length=64, null=True, verbose_name='型号'), |
||||||
|
), |
||||||
|
migrations.AddField( |
||||||
|
model_name='appudid', |
||||||
|
name='imei', |
||||||
|
field=models.CharField(blank=True, max_length=64, null=True, verbose_name='型号'), |
||||||
|
), |
||||||
|
migrations.AlterField( |
||||||
|
model_name='appudid', |
||||||
|
name='product', |
||||||
|
field=models.CharField(blank=True, max_length=64, null=True, verbose_name='产品'), |
||||||
|
), |
||||||
|
migrations.AlterField( |
||||||
|
model_name='appudid', |
||||||
|
name='serial', |
||||||
|
field=models.CharField(blank=True, max_length=64, null=True, verbose_name='序列号'), |
||||||
|
), |
||||||
|
migrations.AlterField( |
||||||
|
model_name='appudid', |
||||||
|
name='version', |
||||||
|
field=models.CharField(blank=True, max_length=64, null=True, verbose_name='型号'), |
||||||
|
), |
||||||
|
] |
@ -0,0 +1,18 @@ |
|||||||
|
# Generated by Django 3.0.3 on 2020-04-16 10:31 |
||||||
|
|
||||||
|
from django.db import migrations, models |
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration): |
||||||
|
|
||||||
|
dependencies = [ |
||||||
|
('api', '0029_auto_20200416_0915'), |
||||||
|
] |
||||||
|
|
||||||
|
operations = [ |
||||||
|
migrations.AddField( |
||||||
|
model_name='appudid', |
||||||
|
name='updated_time', |
||||||
|
field=models.DateTimeField(auto_now=True, verbose_name='更新时间'), |
||||||
|
), |
||||||
|
] |
@ -0,0 +1,18 @@ |
|||||||
|
# Generated by Django 3.0.3 on 2020-04-23 17:29 |
||||||
|
|
||||||
|
from django.db import migrations, models |
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration): |
||||||
|
|
||||||
|
dependencies = [ |
||||||
|
('api', '0030_appudid_updated_time'), |
||||||
|
] |
||||||
|
|
||||||
|
operations = [ |
||||||
|
migrations.AddField( |
||||||
|
model_name='appudid', |
||||||
|
name='is_signed', |
||||||
|
field=models.BooleanField(default=False, verbose_name='是否完成签名打包'), |
||||||
|
), |
||||||
|
] |
@ -0,0 +1,49 @@ |
|||||||
|
# Generated by Django 3.0.3 on 2020-04-25 15:30 |
||||||
|
|
||||||
|
from django.conf import settings |
||||||
|
from django.db import migrations, models |
||||||
|
import django.db.models.deletion |
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration): |
||||||
|
|
||||||
|
dependencies = [ |
||||||
|
('api', '0031_appudid_is_signed'), |
||||||
|
] |
||||||
|
|
||||||
|
operations = [ |
||||||
|
migrations.CreateModel( |
||||||
|
name='APPSuperSignUsedInfo', |
||||||
|
fields=[ |
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
||||||
|
('created_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), |
||||||
|
('updated_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')), |
||||||
|
('app_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.Apps', verbose_name='属于哪个APP')), |
||||||
|
('udid', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.AppUDID', verbose_name='所消耗的udid')), |
||||||
|
('user_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='用户ID')), |
||||||
|
], |
||||||
|
options={ |
||||||
|
'verbose_name': '设备使用统计', |
||||||
|
'verbose_name_plural': '设备使用统计', |
||||||
|
}, |
||||||
|
), |
||||||
|
migrations.CreateModel( |
||||||
|
name='AppIOSDeveloperInfo', |
||||||
|
fields=[ |
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
||||||
|
('name', models.CharField(max_length=64, unique=True, verbose_name='存储名字')), |
||||||
|
('email', models.EmailField(blank=True, max_length=64, null=True, unique=True, verbose_name='email address')), |
||||||
|
('password', models.CharField(max_length=64)), |
||||||
|
('is_actived', models.BooleanField(default=False, verbose_name='是否已经激活')), |
||||||
|
('usable_number', models.IntegerField(default=100, verbose_name='可使用设备数')), |
||||||
|
('use_number', models.IntegerField(default=0, verbose_name='已消耗设备数')), |
||||||
|
('created_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), |
||||||
|
('updated_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')), |
||||||
|
('user_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='用户ID')), |
||||||
|
], |
||||||
|
options={ |
||||||
|
'verbose_name': '苹果开发者账户', |
||||||
|
'verbose_name_plural': '苹果开发者账户', |
||||||
|
}, |
||||||
|
), |
||||||
|
] |
@ -0,0 +1,23 @@ |
|||||||
|
# Generated by Django 3.0.3 on 2020-04-25 16:01 |
||||||
|
|
||||||
|
from django.db import migrations, models |
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration): |
||||||
|
|
||||||
|
dependencies = [ |
||||||
|
('api', '0032_appiosdeveloperinfo_appsupersignusedinfo'), |
||||||
|
] |
||||||
|
|
||||||
|
operations = [ |
||||||
|
migrations.AddField( |
||||||
|
model_name='appudid', |
||||||
|
name='binary_file', |
||||||
|
field=models.CharField(blank=True, max_length=128, null=True, verbose_name='签名包名称'), |
||||||
|
), |
||||||
|
migrations.AlterField( |
||||||
|
model_name='appiosdeveloperinfo', |
||||||
|
name='name', |
||||||
|
field=models.CharField(max_length=64, unique=True, verbose_name='开发者标识'), |
||||||
|
), |
||||||
|
] |
@ -0,0 +1,18 @@ |
|||||||
|
# Generated by Django 3.0.3 on 2020-04-25 16:12 |
||||||
|
|
||||||
|
from django.db import migrations, models |
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration): |
||||||
|
|
||||||
|
dependencies = [ |
||||||
|
('api', '0033_auto_20200425_1601'), |
||||||
|
] |
||||||
|
|
||||||
|
operations = [ |
||||||
|
migrations.AddField( |
||||||
|
model_name='appiosdeveloperinfo', |
||||||
|
name='certid', |
||||||
|
field=models.CharField(blank=True, max_length=64, null=True, verbose_name='超级签名自动创建证书ID'), |
||||||
|
), |
||||||
|
] |
@ -0,0 +1,96 @@ |
|||||||
|
#!/usr/bin/env python |
||||||
|
# -*- coding:utf-8 -*- |
||||||
|
# project: 4月 |
||||||
|
# author: liuyu |
||||||
|
# date: 2020/4/24 |
||||||
|
|
||||||
|
from api.utils.app.shellcmds import shell_command,use_user_pass |
||||||
|
from fir_ser.settings import SUPER_SIGN_ROOT |
||||||
|
import os |
||||||
|
from api.utils.app.randomstrings import make_app_uuid |
||||||
|
|
||||||
|
def exec_shell(cmd,remote=False): |
||||||
|
if remote: |
||||||
|
hostip="10.66.6.66" |
||||||
|
port=65534 |
||||||
|
user="root" |
||||||
|
passwd="root" |
||||||
|
result = use_user_pass(hostip,port,user,passwd,cmd) |
||||||
|
print(result) |
||||||
|
return result |
||||||
|
else: |
||||||
|
result = shell_command(cmd) |
||||||
|
print(result) |
||||||
|
return result |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class AppDeveloperApi(object): |
||||||
|
def __init__(self,username,password,certid): |
||||||
|
self.username = username |
||||||
|
self.password = password |
||||||
|
self.certid = certid |
||||||
|
script_path=os.path.join(SUPER_SIGN_ROOT,'scripts','apple_api.rb') |
||||||
|
self.cmd = "ruby %s '%s' '%s'" %(script_path,self.username,self.password) |
||||||
|
|
||||||
|
def create_cert(self,user_obj): |
||||||
|
cert_dir_name = make_app_uuid(user_obj,self.username) |
||||||
|
cert_dir_path = os.path.join(SUPER_SIGN_ROOT,cert_dir_name) |
||||||
|
if not os.path.isdir(cert_dir_path): |
||||||
|
os.makedirs(cert_dir_path) |
||||||
|
file_format_path_name = os.path.join(cert_dir_path,cert_dir_name) |
||||||
|
self.cmd=self.cmd + " cert add '%s'" %(file_format_path_name) |
||||||
|
result = exec_shell(self.cmd) |
||||||
|
print(result) |
||||||
|
|
||||||
|
def get_profile(self,bundleId,app_id,device_udid,device_name,provisionName): |
||||||
|
self.cmd=self.cmd + " profile add %s %s %s %s %s '%s'" %(bundleId,app_id,device_udid,device_name,self.certid,provisionName) |
||||||
|
result = exec_shell(self.cmd) |
||||||
|
print(result) |
||||||
|
|
||||||
|
def del_profile(self,bundleId,app_id): |
||||||
|
self.cmd=self.cmd + " profile del %s %s" %(bundleId,app_id) |
||||||
|
result = exec_shell(self.cmd) |
||||||
|
print(result) |
||||||
|
|
||||||
|
def set_device_status(self,status,device_udid): |
||||||
|
if status == "enable": |
||||||
|
self.cmd=self.cmd + " device enable %s" %(device_udid) |
||||||
|
else: |
||||||
|
self.cmd=self.cmd + " device disable %s" %(device_udid) |
||||||
|
result = exec_shell(self.cmd) |
||||||
|
print(result) |
||||||
|
|
||||||
|
def add_device(self,device_udid,device_name): |
||||||
|
self.cmd=self.cmd + " device add %s %s" %(device_udid,device_name) |
||||||
|
result = exec_shell(self.cmd) |
||||||
|
print(result) |
||||||
|
|
||||||
|
def add_app(self,bundleId,app_id): |
||||||
|
self.cmd=self.cmd + " app add %s %s" %(bundleId,app_id) |
||||||
|
result = exec_shell(self.cmd) |
||||||
|
print(result) |
||||||
|
|
||||||
|
def del_app(self,bundleId): |
||||||
|
self.cmd=self.cmd + " app del %s " %(bundleId) |
||||||
|
result = exec_shell(self.cmd) |
||||||
|
print(result) |
||||||
|
|
||||||
|
# appdev = AppDeveloperApi("hehehuyu521@163.com","Hehehuyu123") |
||||||
|
# appdev.create_cert() |
||||||
|
# appdev.get_profile('com.hehegames.NenJiangMaJiang',"e6f0c1aeee6853af9c21651654a812e7","6dd86c12ab5506a1f7e45b0f58b6b1448f5cdf54","iPad5,1") |
||||||
|
# # e6f0c1aeee6853af9c21651654a812e7_dis.mobileprovision |
||||||
|
|
||||||
|
class ResignApp(object): |
||||||
|
|
||||||
|
def __init__(self,my_local_key,app_dev_pem): |
||||||
|
self.my_local_key=my_local_key |
||||||
|
self.app_dev_pem = app_dev_pem |
||||||
|
# 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) |
||||||
|
|
||||||
|
def sign(self,new_profile,org_ipa,new_ipa): |
||||||
|
|
||||||
|
self.cmd = self.cmd + " -p %s -o %s %s" %(new_profile,new_ipa,org_ipa) |
||||||
|
result = exec_shell(self.cmd) |
||||||
|
print(result) |
@ -0,0 +1,127 @@ |
|||||||
|
#!/usr/bin/env python |
||||||
|
# -*- coding:utf-8 -*- |
||||||
|
# project: 3月 |
||||||
|
# author: liuyu |
||||||
|
# date: 2020/3/6 |
||||||
|
|
||||||
|
import time,re,os |
||||||
|
from subprocess import Popen, PIPE |
||||||
|
import logging |
||||||
|
import paramiko,json |
||||||
|
import socket |
||||||
|
|
||||||
|
def default_result(): |
||||||
|
return {'exit_code': '99', 'return_info': 'Failed to run, function_name is not existed'} |
||||||
|
|
||||||
|
|
||||||
|
def portisonline(host,port): |
||||||
|
result={} |
||||||
|
sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
||||||
|
sk.settimeout(3) |
||||||
|
result["host"] = host |
||||||
|
result["port"]=port |
||||||
|
result["functionname"]="CHECK_HOST_ONLINE:" |
||||||
|
try: |
||||||
|
sk.connect((host,port)) |
||||||
|
result["message"]="Connection success" |
||||||
|
result["code"]=0 |
||||||
|
except Exception: |
||||||
|
result["message"]="SSH Port Connection refused" |
||||||
|
result["code"]=1 |
||||||
|
sk.close() |
||||||
|
return result |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class SSHConnection(object): |
||||||
|
def __init__(self, host, port, username, password): |
||||||
|
self._host = host |
||||||
|
self._port = port |
||||||
|
self._username = username |
||||||
|
self._password = password |
||||||
|
self._transport = None |
||||||
|
self._sftp = None |
||||||
|
self._client = None |
||||||
|
self._connect() |
||||||
|
|
||||||
|
def _connect(self): |
||||||
|
transport = paramiko.Transport((self._host, self._port)) |
||||||
|
transport.connect(username=self._username, password=self._password) |
||||||
|
self._transport = transport |
||||||
|
|
||||||
|
#下载 |
||||||
|
def download(self, remotepath, localpath): |
||||||
|
if self._sftp is None: |
||||||
|
self._sftp = paramiko.SFTPClient.from_transport(self._transport) |
||||||
|
self._sftp.get(remotepath, localpath) |
||||||
|
self.close() |
||||||
|
|
||||||
|
#上传 |
||||||
|
def put(self, localpath, remotepath): |
||||||
|
if self._sftp is None: |
||||||
|
self._sftp = paramiko.SFTPClient.from_transport(self._transport) |
||||||
|
self.exec_command('mkdir -p %s'%(os.path.dirname(remotepath))) |
||||||
|
self._sftp.put(localpath, remotepath) |
||||||
|
self.close() |
||||||
|
|
||||||
|
|
||||||
|
#执行命令 |
||||||
|
def exec_command(self, command): |
||||||
|
if self._client is None: |
||||||
|
self._client = paramiko.SSHClient() |
||||||
|
self._client._transport = self._transport |
||||||
|
stdin, stdout, stderr = self._client.exec_command(command) |
||||||
|
data = stdout.read() |
||||||
|
if len(data) > 0: |
||||||
|
return {'status':0,'infos':data} |
||||||
|
err = stderr.read() |
||||||
|
if len(err) > 0: |
||||||
|
return {'status':1,'infos':err} |
||||||
|
return {'status': 0, 'infos': data} |
||||||
|
|
||||||
|
def close(self): |
||||||
|
if self._transport: |
||||||
|
self._transport.close() |
||||||
|
if self._client: |
||||||
|
self._client.close() |
||||||
|
|
||||||
|
def shell_command(cmdstrs): |
||||||
|
cmdresult = re.split(r'\s+', cmdstrs) |
||||||
|
result = default_result() |
||||||
|
result['return_info'] = '' |
||||||
|
shell_start_time = time.time() |
||||||
|
child = Popen(cmdresult, shell=True, stdout=PIPE, stderr=PIPE) |
||||||
|
out, err = child.communicate() |
||||||
|
shell_end_time = time.time() |
||||||
|
result['shell_run_time'] = shell_end_time - shell_start_time |
||||||
|
out = out.strip(b'\n') |
||||||
|
result['return_info'] = out |
||||||
|
result['exit_code'] = child.returncode |
||||||
|
logging.info(u'shell: %s - %s%s - %s%d' % (cmdstrs, 'return_info: ', out, 'exit_code: ', child.returncode)) |
||||||
|
return result |
||||||
|
|
||||||
|
def use_user_pass(hostip,port,user,passwd,cmdstrs): |
||||||
|
result = default_result() |
||||||
|
checkinfo = portisonline(hostip, port) |
||||||
|
if checkinfo["code"] != 0: |
||||||
|
result['shell_run_time'] = 0 |
||||||
|
result['return_info'] = json.dumps(checkinfo) |
||||||
|
result['exit_code'] = checkinfo["code"] |
||||||
|
else: |
||||||
|
conn = SSHConnection(hostip, port, user, passwd) |
||||||
|
result['return_info'] = '' |
||||||
|
shell_start_time = time.time() |
||||||
|
out=conn.exec_command(cmdstrs) |
||||||
|
shell_end_time = time.time() |
||||||
|
result['shell_run_time'] = shell_end_time - shell_start_time |
||||||
|
outs =str(out['infos'],'utf-8') |
||||||
|
outs = outs.strip('\n') |
||||||
|
result['return_info'] = outs |
||||||
|
result['exit_code'] = out['status'] |
||||||
|
# logging.info(u'shell: %s - %s%s - %s%d' % (cmdstrs, 'return_info: ', out, 'exit_code: ', out['status'])) |
||||||
|
print('host: %s user:%s - shell: %s - %s%s - %s%d' % (hostip,user,cmdstrs, 'return_info: ', out, 'exit_code: ', out['status'])) |
||||||
|
conn.close() |
||||||
|
return result |
||||||
|
|
||||||
|
|
@ -0,0 +1,163 @@ |
|||||||
|
#!/usr/bin/env python |
||||||
|
# -*- coding:utf-8 -*- |
||||||
|
# project: 3月 |
||||||
|
# author: liuyu |
||||||
|
# date: 2020/3/6 |
||||||
|
|
||||||
|
import uuid, xmltodict,os |
||||||
|
from fir_ser.settings import SUPER_SIGN_ROOT,MEDIA_ROOT,SERVER_DOMAIN |
||||||
|
from api.utils.app.iossignapi import AppDeveloperApi,ResignApp |
||||||
|
from api.models import APPSuperSignUsedInfo,AppUDID,AppIOSDeveloperInfo,AppReleaseInfo |
||||||
|
from api.utils.app.randomstrings import make_app_uuid,make_from_user_uuid |
||||||
|
from django.db.models import F |
||||||
|
|
||||||
|
def udid_bytes_to_dict(xml_stream): |
||||||
|
new_uuid_info = {} |
||||||
|
try: |
||||||
|
a = xml_stream.find('<plist') |
||||||
|
b = xml_stream.find('</plist>') |
||||||
|
xml_dict = xmltodict.parse(xml_stream[a:b + 8]) # 解析xml字符串 |
||||||
|
for i in range(len(xml_dict['plist']['dict']['key'])): |
||||||
|
new_uuid_info[xml_dict['plist']['dict']['key'][i].lower()] = xml_dict['plist']['dict']['string'][i] |
||||||
|
except Exception as e: |
||||||
|
print(e) |
||||||
|
return new_uuid_info |
||||||
|
|
||||||
|
|
||||||
|
def make_udid_mobileconfig(udid_url, PayloadOrganization, PayloadUUID=uuid.uuid1(), PayloadDescription='本文件仅用来获取设备ID', |
||||||
|
PayloadDisplayName='查询设备UDID'): |
||||||
|
# <!--参考:https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/iPhoneOTAConfiguration/ConfigurationProfileExamples/ConfigurationProfileExamples.html--> |
||||||
|
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"> |
||||||
|
<plist version="1.0"> |
||||||
|
<dict> |
||||||
|
<key>PayloadContent</key> |
||||||
|
<dict> |
||||||
|
<key>URL</key> |
||||||
|
<string>%s</string> |
||||||
|
<key>DeviceAttributes</key> |
||||||
|
<array> |
||||||
|
<string>SERIAL</string> |
||||||
|
<string>UDID</string> |
||||||
|
<string>IMEI</string> |
||||||
|
<string>ICCID</string> |
||||||
|
<string>VERSION</string> |
||||||
|
<string>PRODUCT</string> |
||||||
|
</array> |
||||||
|
</dict> |
||||||
|
<key>PayloadOrganization</key> |
||||||
|
<string>%s</string> |
||||||
|
<key>PayloadDisplayName</key> |
||||||
|
<string>%s</string> |
||||||
|
<key>PayloadVersion</key> |
||||||
|
<integer>1</integer> |
||||||
|
<key>PayloadUUID</key> |
||||||
|
<string>%s</string> |
||||||
|
<key>PayloadIdentifier</key> |
||||||
|
<string>%s.profile-service</string> |
||||||
|
<key>PayloadDescription</key> |
||||||
|
<string>%s</string> |
||||||
|
<key>PayloadType</key> |
||||||
|
<string>Profile Service</string> |
||||||
|
</dict> |
||||||
|
</plist>''' % (udid_url, PayloadOrganization, PayloadDisplayName, PayloadUUID, PayloadOrganization, PayloadDescription) |
||||||
|
return mobileconfig |
||||||
|
|
||||||
|
|
||||||
|
def get_post_udid_url(request, short): |
||||||
|
server_domain = get_http_server_doamin(request) |
||||||
|
|
||||||
|
PATH_INFO = request.META.get('PATH_INFO') |
||||||
|
PATH_INFO_lists = PATH_INFO.strip('/').split('/') |
||||||
|
PATH_INFO_lists[-1] = 'udid' |
||||||
|
PATH_INFO_lists.pop(-2) |
||||||
|
PATH_INFO_lists.append(short) |
||||||
|
PATH_INFO_lists.insert(0, server_domain) |
||||||
|
udid_url = "/".join(PATH_INFO_lists) |
||||||
|
return udid_url |
||||||
|
|
||||||
|
|
||||||
|
def get_http_server_doamin(request): |
||||||
|
server_domain = SERVER_DOMAIN.get('POST_UDID_DOMAIN', None) |
||||||
|
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_redirect_server_domain(request): |
||||||
|
server_domain = SERVER_DOMAIN.get('REDIRECT_UDID_DOMAIN', None) |
||||||
|
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 |
||||||
|
|
||||||
|
|
||||||
|
class IosUtils(object): |
||||||
|
def __init__(self,udid_info,app_obj): |
||||||
|
self.udid_info=udid_info |
||||||
|
self.app_obj = app_obj |
||||||
|
self.user_obj = app_obj.user_id |
||||||
|
self.get_developer_auth() |
||||||
|
|
||||||
|
|
||||||
|
def get_developer_auth(self): |
||||||
|
developer_obj = AppIOSDeveloperInfo.objects.filter(user_id=self.user_obj,is_actived=True,use_number__lte=F("usable_number")).first() |
||||||
|
auth = { |
||||||
|
"username":developer_obj.email, |
||||||
|
"password": developer_obj.password, |
||||||
|
"certid":developer_obj.certid |
||||||
|
} |
||||||
|
self.auth = auth |
||||||
|
|
||||||
|
|
||||||
|
def download_profile(self): |
||||||
|
app_api_obj = AppDeveloperApi(** self.auth) |
||||||
|
bundleId = self.app_obj.bundle_id |
||||||
|
app_id=self.app_obj.app_id |
||||||
|
device_udid= self.udid_info.get('udid') |
||||||
|
device_name=self.udid_info.get('product') |
||||||
|
app_api_obj.get_profile(bundleId,app_id,device_udid,device_name,self.get_profile_full_path()) |
||||||
|
|
||||||
|
def get_profile_full_path(self): |
||||||
|
cert_dir_name = make_app_uuid(self.user_obj,self.auth.get("username")) |
||||||
|
cert_dir_path = os.path.join(SUPER_SIGN_ROOT,cert_dir_name) |
||||||
|
file_format_path_name = os.path.join(cert_dir_path,cert_dir_name,"profile") |
||||||
|
if not os.path.isdir(file_format_path_name): |
||||||
|
os.makedirs(file_format_path_name) |
||||||
|
provisionName = os.path.join(file_format_path_name,self.app_obj.app_id) |
||||||
|
return provisionName+ '.mobileprovision' |
||||||
|
|
||||||
|
def resign(self): |
||||||
|
self.download_profile() |
||||||
|
cert_dir_name = make_app_uuid(self.app_obj.user_id,self.auth.get("username")) |
||||||
|
cert_dir_path = os.path.join(SUPER_SIGN_ROOT,cert_dir_name) |
||||||
|
if not os.path.isdir(cert_dir_path): |
||||||
|
os.makedirs(cert_dir_path) |
||||||
|
file_format_path_name = os.path.join(cert_dir_path,cert_dir_name) |
||||||
|
|
||||||
|
my_local_key=file_format_path_name+".key" |
||||||
|
app_dev_pem =file_format_path_name+".pem" |
||||||
|
ResignAppObj = ResignApp(my_local_key,app_dev_pem) |
||||||
|
|
||||||
|
random_file_name = make_from_user_uuid(self.user_obj) |
||||||
|
|
||||||
|
release_obj = AppReleaseInfo.objects.filter(app_id=self.app_obj,is_master=True).first() |
||||||
|
|
||||||
|
org_file = os.path.join(MEDIA_ROOT, release_obj.release_id + ".ipa") |
||||||
|
new_file = os.path.join(MEDIA_ROOT, random_file_name + ".ipa") |
||||||
|
ResignAppObj.sign(self.get_profile_full_path(),org_file,new_file) |
||||||
|
|
||||||
|
newdata={ |
||||||
|
"is_signed":True, |
||||||
|
"binary_file":random_file_name + ".ipa" |
||||||
|
} |
||||||
|
AppUDID.objects.filter(app_id=self.app_obj,udid=self.udid_info.get('udid')).update(**newdata) |
@ -1,3 +0,0 @@ |
|||||||
from django.shortcuts import render |
|
||||||
|
|
||||||
# Create your views here. |
|
@ -0,0 +1,157 @@ |
|||||||
|
#!/usr/bin/ruby |
||||||
|
# -*- coding: UTF-8 -*- |
||||||
|
|
||||||
|
require "spaceship" |
||||||
|
|
||||||
|
class DevelopPortalHandle |
||||||
|
def login(username,password) |
||||||
|
Spaceship::Portal.login(username,password) |
||||||
|
end |
||||||
|
|
||||||
|
def createCert(file_format_path_name) |
||||||
|
csr, pkey = Spaceship::Portal.certificate.create_certificate_signing_request |
||||||
|
cert=Spaceship::Portal.certificate.production.create!(csr: csr) |
||||||
|
File.write(file_format_path_name+".key",pkey) |
||||||
|
File.write(file_format_path_name+".cer",cert.download_raw) |
||||||
|
File.write(file_format_path_name+".pem",cert.download) |
||||||
|
File.write(file_format_path_name+".info",cert) |
||||||
|
end |
||||||
|
|
||||||
|
def createApp(appid,appname) |
||||||
|
app = Spaceship::Portal.app.find(appid) |
||||||
|
if !app then |
||||||
|
app = Spaceship::Portal.app.create!(bundle_id: appid, name: appname) |
||||||
|
app.update_service(Spaceship::Portal.app_service.push_notification.on) |
||||||
|
app.update_service(Spaceship::Portal.app_service.vpn_configuration.on) |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
def deleteApp(appid) |
||||||
|
app = Spaceship::Portal.app.find(appid) |
||||||
|
if app then |
||||||
|
app.delete! |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
#appstore or inHouse |
||||||
|
def createDistributionProvision(provisioningClass,appid,provisionName,certid) |
||||||
|
cert = Spaceship::Portal.certificate.Production.find(id=certid) |
||||||
|
if !cert then |
||||||
|
cert = Spaceship::Portal.certificate.production.all.last |
||||||
|
end |
||||||
|
profile = provisioningClass.create!(bundle_id: appid,certificate:cert,name:provisionName + '_dis') |
||||||
|
return profile |
||||||
|
end |
||||||
|
|
||||||
|
#appstore or inHouse |
||||||
|
def downloadDistributionProvision(provisioningClass,appid,provisionName,certid) |
||||||
|
#查找有没有provision文件 |
||||||
|
filtered_profiles = provisioningClass.find_by_bundle_id(bundle_id: appid) |
||||||
|
profile = nil |
||||||
|
if 0 < filtered_profiles.length then |
||||||
|
profile = filtered_profiles[0] |
||||||
|
elsif 0 == filtered_profiles.length then |
||||||
|
profile = createDistributionProvision(provisioningClass,appid,provisionName,certid) |
||||||
|
end |
||||||
|
|
||||||
|
#没有找到就创建,找到就下载 |
||||||
|
File.write(provisionName, profile.download) |
||||||
|
return provisionFileName |
||||||
|
end |
||||||
|
|
||||||
|
def delete_profile(provisioningClass,appid) |
||||||
|
filtered_profiles = provisioningClass.find_by_bundle_id(bundle_id: appid) |
||||||
|
profile = nil |
||||||
|
if 0 < filtered_profiles.length then |
||||||
|
profile = filtered_profiles[0] |
||||||
|
profile.delete! |
||||||
|
end |
||||||
|
end |
||||||
|
def addDevice(device_name,device_udid) |
||||||
|
device = Spaceship::Portal.device.find_by_udid(device_udid, include_disabled: false) |
||||||
|
if !device then |
||||||
|
Spaceship::Portal.device.create!(name: device_name, udid: device_udid) |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
def enableDevice(device_udid) |
||||||
|
device=Spaceship::Portal.device.find_by_udid(device_udid, include_disabled: true) |
||||||
|
if device then |
||||||
|
device.enable! |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
def disableDevice(device_udid) |
||||||
|
device = Spaceship::Portal.device.find_by_udid(device_udid) |
||||||
|
if device then |
||||||
|
device.disable! |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
end |
||||||
|
|
||||||
|
handle = DevelopPortalHandle.new() |
||||||
|
handle.login(ARGV[0],ARGV[1]) |
||||||
|
function = ARGV[2] |
||||||
|
|
||||||
|
case function |
||||||
|
when "device" |
||||||
|
action = ARGV[3] |
||||||
|
device_udid = ARGV[4] |
||||||
|
device_name = ARGV[5] |
||||||
|
|
||||||
|
case action |
||||||
|
when "add" |
||||||
|
device_name = device_udid+','+device_udid |
||||||
|
handle.addDevice(device_name,device_udid) |
||||||
|
when "enable" |
||||||
|
handle.enableDevice(device_udid) |
||||||
|
when "disable" |
||||||
|
handle.disableDevice(device_udid) |
||||||
|
end |
||||||
|
|
||||||
|
when "app" |
||||||
|
action = ARGV[3] |
||||||
|
app_id = ARGV[4] |
||||||
|
app_name = ARGV[5] |
||||||
|
appid = app_id+app_name |
||||||
|
|
||||||
|
case action |
||||||
|
when "add" |
||||||
|
handle.createApp(appid,app_name) |
||||||
|
when "del" |
||||||
|
handle.deleteApp(appid) |
||||||
|
handle.delete_profile(Spaceship::Portal.provisioning_profile.ad_hoc,appid) |
||||||
|
end |
||||||
|
when "profile" |
||||||
|
action = ARGV[3] |
||||||
|
app_id = ARGV[4] |
||||||
|
app_name = ARGV[5] |
||||||
|
appid = app_id+app_name |
||||||
|
|
||||||
|
case action |
||||||
|
when "add" |
||||||
|
device_udid = ARGV[6] |
||||||
|
device_name = ARGV[7] |
||||||
|
certid = ARGV[8] |
||||||
|
provisionName = ARGV[9] |
||||||
|
handle.createApp(appid,app_name) |
||||||
|
handle.addDevice(device_name,device_udid) |
||||||
|
provisionPath = handle.downloadDistributionProvision(Spaceship::Portal.provisioning_profile.ad_hoc,appid,provisionName,certid) |
||||||
|
when "del" |
||||||
|
handle.delete_profile(Spaceship::Portal.provisioning_profile.ad_hoc,appid) |
||||||
|
end |
||||||
|
|
||||||
|
when "cert" |
||||||
|
action = ARGV[3] |
||||||
|
file_format_path_name = ARGV[4] |
||||||
|
case action |
||||||
|
when "add" |
||||||
|
handle.createCert(file_format_path_name) |
||||||
|
end |
||||||
|
|
||||||
|
else |
||||||
|
puts "error" |
||||||
|
end |
||||||
|
|
||||||
|
|
Loading…
Reference in new issue