Exemple #1
0
def _refresh_certs():
    p = Popen("security find-identity -p codesigning -v",
              bufsize=1,
              stdout=subprocess.PIPE,
              stderr=subprocess.PIPE,
              shell=True)
    expire = now() + 30000
    while p.poll() is None:
        if now() < expire:
            gevent.sleep(1)
    expr = re.compile(r'\s*\d+\)\s*\S+\s+"([^"]+(\s+\(.+\)))"')
    for each in map(lambda x: x.decode("utf8").strip(), p.stdout.readlines()):
        result = expr.match(each)
        if not result:
            continue
        if "REVOKED" in each:
            Log("过期的证书[%s]" % each)
            continue
        # noinspection PyBroadException
        try:
            cert, _id = result.groups()
            _certs[cert] = _id.strip()[1:-2]
            _certs[cert[:-len(_id)]] = _id.strip()[1:-2]
            Log("有效的证书[%s]" % each)
        except:
            Log("跳过[%s]" % each)
Exemple #2
0
def info(_req: HttpRequest, project: str, uuid: str = ""):
    _project = IosProjectInfo.objects.filter(
        project=project).first()  # type: IosProjectInfo
    udid = ""
    if not _project:
        return {}
    ret = str_json(_project.comments)
    ready = False

    if uuid:
        _user = UserInfo.objects.filter(uuid=uuid).first()  # type: UserInfo
        if _user:
            ready = True
            udid = _user.udid
        else:
            Log("上传的uuid无效[%s]" % uuid)
    else:
        uuid = _req.get_signed_cookie("uuid", "", salt="zhihu")
        _user = UserInfo.objects.filter(uuid=uuid).first()  # type: UserInfo
        if _user:
            ready = True
            udid = _user.udid
        else:
            Log("cookie中的uuid无效[%s]" % uuid)

    if ready:
        ret.update({
            "ready": True,
        })
        _task = TaskInfo.objects.filter(uuid=uuid).first()  # type:TaskInfo
        if _task:
            if _task.state == "fail" or _task.expire.timestamp() * 1000 < now(
            ):
                __add_task(_user)

    else:
        uuid = _newbee(_project)
        ret.update({
            "ready": False,
        })

    ret.update({
        "uuid": uuid,
    })
    rsp = JsonResponse({
        "ret": 0,
        "result": ret,
        "download_id": random_str(32),
    })
    rsp.set_signed_cookie("uuid", uuid, salt="zhihu", expires=3600 * 24)
    if udid:
        rsp.set_signed_cookie("udid",
                              _user.udid,
                              salt="zhihu",
                              expires=300 * 3600 * 24)
    return rsp
Exemple #3
0
def _wait_code(info: IosAccountInfo,
               session: requests.Session,
               ts,
               save_now=False):
    """
    等待二次提交的需要
    """
    Log("等待[%s]二次验证" % info.account)
    # last = info.security_code
    expire = now() + 1200 * 1000
    while now() < expire:
        gevent.sleep(1)
        for data in message_from_topic(__pub, is_json=True, limit=1):
            if data.get("ts") > ts:
                if data.get("code") and data.get("account") in {
                        info.account, "*"
                }:
                    rsp = session.post(
                        "https://idmsa.apple.com/appleauth/auth/verify/phone/securitycode",
                        json={
                            "securityCode": {
                                "code": str(data.get("code")),
                            },
                            "phoneNumber": {
                                "id": 1,
                            },
                            "mode": "sms",
                        })
                    # Log("[%s] %s" % (rsp.status_code, rsp.json()))
                    # rsp = session.post("https://idmsa.apple.com/appleauth/auth/verify/trusteddevice/securitycode", json={
                    #     "securityCode": {"code": data["code"]},
                    # })
                    if rsp.status_code != 200:
                        Log("账号[%s]验证校验码[%s]失败[%s]" %
                            (info.account, data.get("code"), rsp.status_code))
                    # if rsp.status_code != 204:
                    #     Log("账号[%s]验证校验码[%s]失败[%s]" % (info.account, data.get("code"), rsp.status_code))
                    #     continue
                    rsp = session.get(
                        "https://idmsa.apple.com/appleauth/auth/2sv/trust")
                    if rsp.status_code == 204:
                        session.cookies.update(
                            {"__expire": str(now() + 6 * 3600 * 1000)})
                        if save_now:
                            info.cookie = json_str(session.cookies)
                            info.save()
                        Log("账号[%s]登录成功" % info.account)
                        return session
    raise Fail("登录二次验证超时")
Exemple #4
0
def __list_all_devices(_config: IosAccountHelper):
    ret = _config.post(
        "获取所有的列表",
        "https://developer.apple.com/services-account/QH65B2/account/ios/device/listDevices.action?teamId=",
        data={
            "includeRemovedDevices": True,
            "includeAvailability": True,
            "pageNumber": 1,
            "pageSize": 100,
            "sort": "status%3dasc",
            "teamId": _config.team_id,
        },
        log=False)
    for device in ret["devices"]:  # type: Dict
        _reg_device(
            device["deviceId"], device["deviceNumber"],
            device.get("model", device.get("deviceClass", "#UNKNOWN#")),
            device.get("serialNumber", "#UNKNOWN#"))
    # 更新一下info
    devices = list(map(lambda x: x["deviceNumber"], ret["devices"]))
    if json_str(devices) != _config.info.devices:
        Log("更新设备列表[%s]数量[%s]=>[%s]" %
            (_config.account, _config.info.devices_num, len(devices)))
        _config.info.devices = json_str(devices)
        _config.info.devices_num = len(devices)
        _config.info.save()
Exemple #5
0
def db_get_list(key_list: Sequence[str],
                allow_not_found=True,
                fail=True,
                model=None):
    if len(key_list) == 0:
        return []
    start = time.time()
    orig_ret = db_model.mget(key_list)
    cost = time.time() - start
    if cost > 0.01:
        Log("耗时的db操作[%s][%s]" % (len(key_list), key_list[:10]))
    ret = list(filter(lambda x: x is not None, orig_ret))
    if len(ret) != len(key_list):
        if model is not None:
            tmp = model + ":"
            assert len(list(filter(lambda x: not x.startswith(tmp),
                                   key_list))) == 0
        for i, k_v in enumerate(zip(key_list, orig_ret)):
            if k_v[1] is not None:
                continue
            orig_ret[i] = mongo_get(k_v[0], model=model)
        ret = list(filter(lambda x: x is not None, orig_ret))

    if len(ret) != len(key_list):
        if not allow_not_found:
            if fail:
                if isinstance(fail, bool):
                    raise Fail("少了一部分的数据")
                else:
                    raise Fail(fail)
    return ret
Exemple #6
0
def __add_task(_user: UserInfo):
    _account = IosAccountInfo.objects.filter(
        account=_user.account).first()  # type:IosAccountInfo
    _project = IosProjectInfo.objects.filter(
        project=_user.project).first()  # type:IosProjectInfo
    _profile = IosProfileInfo.objects.filter(
        sid="%s:%s" %
        (_user.account, _user.project)).first()  # type:IosProfileInfo
    Assert(_profile, "[%s][%s]证书无效" % (_project.project, _account.account))
    Log("[%s]发布任务[%s]" % (_user.project, _user.account))
    db_session.publish(
        "task:package",
        json_str({
            "cert":
            "iPhone Developer: zhangming luo",
            "cert_p12":
            "",
            "mp_url":
            entry("/apple/download_mp?uuid=%s" % _user.uuid),
            "mp_md5":
            md5bytes(base64decode(_profile.profile)),
            "project":
            _project.project,
            "ipa_url":
            _asset_url("%s/orig.ipa" % _user.project),
            "ipa_md5":
            _project.md5sum,
            "ipa_new":
            "%s_%s.ipa" % (_account.team_id, _account.devices_num),
            "upload_url":
            entry("/apple/upload_ipa?project=%s&account=%s" %
                  (_user.project, _user.account)),
            "ts":
            now(),
        }))
Exemple #7
0
def _reg_cert(_config: IosAccountInfo, cert_req_id, name, cert_id, sn,
              type_str, expire):
    sid = "%s:%s" % (_config.account, name)
    orig = str_json(
        db_model.get("IosCertInfo:%s:%s" % (_config.account, name)) or '{}')
    obj = {
        "name": name,
        "app": _config.account,
        "cert_req_id": cert_req_id,
        "cert_id": cert_id,
        "sn": sn,
        "type_str": type_str,
        "expire": expire,
        "expire_str": date_time_str(expire),
    }
    if orig == obj:
        return cert_req_id
    db_model.set("IosCertInfo:%s:%s" % (_config.account, name),
                 json_str(obj),
                 ex=(expire - now()) // 1000)
    _info = IosCertInfo()
    _info.sid = sid
    _info.app = _config.account
    _info.cert_req_id = cert_req_id
    _info.cert_id = cert_id
    _info.sn = sn
    _info.type_str = type_str
    _info.name = name
    _info.create = now()
    _info.expire = datetime.datetime.utcfromtimestamp(expire // 1000)
    _info.save()
    Log("注册新的证书[%s][%s]" % (name, cert_req_id))
    return cert_req_id
Exemple #8
0
def mongo_get(key: str, model=None, active=True) -> Optional[Dict]:
    if model is not None:
        if not key.startswith(model + ":"):
            return None
    i = key.index(':')
    if i <= 0:
        return None
    model, _id = key[0:i], key[i + 1:]
    if active:
        if active is True:
            active = {"ts": now()}
        ret = mongo(model).find_one_and_update(
            {"_id": key}, {"$set": {
                "__active__": active
            }})
        if ret is not None:
            ret = json.dumps(ret,
                             separators=(',', ':'),
                             sort_keys=True,
                             ensure_ascii=False)
            Log("从mongodb[%s]激活[%s][%s]" % (model, key, ret))
            db_model.set(key, ret)
        return ret
    else:
        return mongo(model).find_one({"_id": _id})
Exemple #9
0
 def __logout(self):
     Log("登出账号[%s]" % self.account)
     _key = "apple:developer:cookie"
     self.__expire = 0
     self.cookie.clear()
     self.info.cookie = "{}"
     self.info.save()
Exemple #10
0
def __add_task(_user: UserInfo):
    _account = IosAccountInfo.objects.get(account=_user.account)
    _project = IosProjectInfo.objects.get(project=_user.project)
    _profile = IosProfileInfo.objects.get(sid="%s:%s" %
                                          (_user.account, _user.project))
    _cert = IosCertInfo.objects.get(
        sid="%s:%s" % (_user.account, str_json_a(_profile.certs)[0]))
    Assert(_profile, "[%s][%s]证书无效" % (_project.project, _account.account))
    Assert(_project.md5sum, "项目[%s]原始ipa还没上传" % _project.project)
    Assert(_cert.cert_p12, "项目[%s]p12还没上传" % _project.project)
    Log("[%s]发布任务[%s]" % (_user.project, _user.account))
    _task, _ = TaskInfo.objects.get_or_create(uuid=_user.uuid)
    _task.state = "none"
    _task.worker = ""
    _task.save()
    resign_ipa.delay(
        **{
            "uuid": _user.uuid,
            "cert": "iPhone Developer: %s" % _cert.name,
            "cert_url": entry("/apple/download_cert?uuid=%s" % _user.uuid),
            "cert_md5": md5bytes(base64decode(_cert.cert_p12)),
            "mp_url": entry("/apple/download_mp?uuid=%s" % _user.uuid),
            "mp_md5": md5bytes(base64decode(_profile.profile)),
            "project": _project.project,
            "ipa_url": entry("/projects/%s/orig.ipa" % _user.project),
            "ipa_md5": _project.md5sum,
            "ipa_new": "%s_%s.ipa" % (_account.team_id, _account.devices_num),
            "upload_url": entry("/apple/upload_ipa?uuid=%s" % _user.uuid),
            "process_url": entry("/apple/task_state?uuid=%s" % _user.uuid),
        })
Exemple #11
0
def __profile_detail(_config: IosAccountHelper, _profile: IosProfileInfo):
    ret = _config.post(
        "获取profile详情",
        "https://developer.apple.com/services-account/QH65B2/account/ios/profile/getProvisioningProfile.action?teamId=",
        data={
            "includeInactiveProfiles": True,
            "provisioningProfileId": _profile.profile_id,
            "teamId": _config.team_id,
        },
    )
    profile = ret["provisioningProfile"]
    devices = list(map(lambda x: x["deviceNumber"], profile["devices"]))
    devices_str = json_str(devices)
    if _profile.devices != devices_str:
        _profile.devices = devices_str
        _profile.devices_num = len(devices)
        __download_profile(_config, _profile)
        Log("更新profile[%s]" % _profile.sid)
        _profile.save()
    certs = []
    for each in profile["certificates"]:
        certs.append(each["certificateId"])
    if _profile.certs != json_str(certs):
        _profile.certs = json_str(certs)
        _profile.save()
Exemple #12
0
def task_state(uuid: str, worker: str = "", state: str = "", auto_start=True):
    _task, _ = TaskInfo.objects.get_or_create(uuid=uuid)
    if state:
        if _task.worker:
            Assert(_task.worker == worker,
                   "越权更改任务[%s]状态[%s]=>[%s]" % (uuid, _task.worker, worker))
        else:
            _task.worker = worker
            _task.save()
        if _task.state != state:
            Log("任务[%s]状态变更[%s]=>[%s]" % (uuid, _task.state, state))
            _task.state = state
            _task.save()
        return {
            "succ": True,
        }
    else:
        if auto_start and _task.state in {"fail", "expire", "none", ""}:
            # noinspection PyTypeChecker
            rebuild({
                "uuid": uuid,
            })
        # 获取当前的状态
        return {
            "code":
            1 if _task.state in {"fail", "expire"} else 0,
            "finished":
            _task.state == "succ",
            "progress":
            "%d%%" % ((_states.index(_task.state) + 1) * 100 / len(_states))
            if _task.state in _states else "0%",
        }
Exemple #13
0
def _refresh_certs():
    expr = re.compile(r'\s*\d+\)\s*\S+\s+"([^"]+(\s+\(.+\)))"')
    for each in _shell_run("security find-identity -p codesigning -v"):
        result = expr.match(each)
        if not result:
            continue
        if "REVOKED" in each:
            Log("过期的证书[%s]" % each)
            continue
        # noinspection PyBroadException
        try:
            cert, _id = result.groups()
            _certs[cert] = _id.strip()[1:-2]
            _certs[cert[:-len(_id)]] = _id.strip()[1:-2]
            Log("有效的证书[%s]" % each)
        except:
            Log("跳过[%s]" % each)
Exemple #14
0
def mongo_index(cate, index, unique=False):
    collection = _mongo(cate)
    if ("%s_1" % index) not in collection.index_information():
        Log("创建mongo索引[%s][%s][unique:%s]" % (cate, index, unique))
        collection.create_index(index,
                                unique=unique,
                                sparse=True,
                                background=True)
Exemple #15
0
def add_device(_content: bytes, uuid: str, udid: str = ""):
    _key = "uuid:%s" % uuid
    _detail = str_json(db_session.get(_key) or "{}")
    _account = _detail.get("account")
    project = _detail["project"]
    if not _detail:
        raise Fail("无效的uuid[%s]" % uuid)
    if not udid:
        # todo: 验证来源
        with Block("提取udid", fail=False):
            udid = re.compile(br"<key>UDID</key>\n\s+<string>(\w+)</string>"
                              ).findall(_content)[0].decode("utf8")
    if not udid:
        # 提取udid失败后删除uuid
        db_session.delete(_key)
        return {
            "succ": False,
        }
    for _user in UserInfo.objects.filter(udid=udid):
        _account = _user.account
        if _user.project == _detail["project"]:
            if uuid != _user.uuid:
                Log("转移设备的[%s]的uuid[%s]=>[%s]" % (udid, uuid, _user.uuid))
                uuid = _user.uuid
                break

    if not _account:
        Log("为设备[%s]分配账号" % udid)
        _account = __fetch_account(udid, project, __add_device)
    else:
        _account = IosAccountInfo.objects.filter(account=_account).first()

    _user = UserInfo(uuid=uuid)
    _user.udid = udid
    _user.project = _detail["project"]
    _user.account = _account.account
    _user.save()
    if test_env():
        # 测试环境可能uuid要重复测
        pass
    else:
        db_session.delete(_key)
    __add_task(_user)
    return HttpResponsePermanentRedirect(
        "https://iosstore.sklxsj.com/detail.php?project=%s" % project)
Exemple #16
0
 def _debug():
     _info, created = IosProjectInfo.objects.get_or_create(sid="test",
                                                           project="test")
     if created:
         Log("初始化一个测试项目")
         _info.bundle_prefix = "com.test"
         _info.save()
     upload_project_ipa._orig_func("test",
                                   read_binary_file("projects/test.ipa"))
Exemple #17
0
def _reg_device(device_id: str, udid: str, model: str, sn: str) -> str:
    # 需要缓存
    _info = IosDeviceInfo()
    _info.udid = udid
    _info.device_id = device_id
    _info.model = model
    _info.sn = sn
    _info.create = now()
    _info.save()
    Log("注册新的设备[%s][%s][%s]" % (udid, device_id, sn))
    return udid
Exemple #18
0
def mapping_get(cate, mapping, prop="_key") -> Optional[str]:
    ret = db_model_ex.get("%s:%s" % (cate, mapping))
    if ret is None:
        if prop is not None and len(prop):
            tmp = mongo(cate).find_one({prop: mapping})
            if tmp is not None:
                Log("激活索引[%s:%s]=>[%s]" % (cate, mapping, tmp["id"]))
                ret = "%s:%s" % (cate, tmp["id"])
                db_model_ex.set("%s:%s" % (cate, mapping),
                                ret,
                                ex=3 * 24 * 3600)
    return ret
Exemple #19
0
def _reg_app(_config: IosAccountInfo, project: str, app_id_id: str, name: str,
             prefix: str, identifier: str):
    sid = "%s:%s" % (_config.account, project)
    _info = IosAppInfo()
    _info.sid = sid
    _info.app = _config.account
    _info.app_id_id = app_id_id
    _info.identifier = identifier
    _info.name = name
    _info.prefix = prefix
    _info.create = now()
    _info.save()
    Log("注册新的app[%s][%s][%s]" % (_config.account, app_id_id, identifier))
Exemple #20
0
def upload_ipa(project: str, account: str, file: bytes):
    base = os.path.join("static/income", project)
    os.makedirs(base, exist_ok=True)
    _info = IosAccountInfo.objects.filter(
        account=account).first()  # type:IosAccountInfo
    Assert(_info, "账号[%s]不存在" % account)
    filename = "%s_%s.ipa" % (_info.team_id, _info.devices_num)
    with open(os.path.join(base, filename), mode="wb") as fout:
        fout.write(file)
    Log("[%s]收到新打包的ipa[%s]" % (account, filename))
    return {
        "succ": True,
    }
Exemple #21
0
def upload_project_ipa(project: str, file: bytes):
    _info = IosProjectInfo.objects.get(project=project)
    base = os.path.join("static/projects", project)
    os.makedirs(base, exist_ok=True)
    with open(os.path.join(base, "orig.ipa"), mode="wb") as fout:
        fout.write(file)
    if _info.md5sum != md5bytes(file):
        _info.md5sum = md5bytes(file)
        _info.save()
        Log("更新工程[%s]的ipa[%s]" % (project, _info.md5sum))
    # todo: 激活更新一下
    return {
        "succ": True,
    }
Exemple #22
0
def _load_awwdrca():
    """
    加载 Apple Worldwide Developer Relations Certification Authority
    """
    for each in _shell_run("security find-certificate -a", succ_only=True):
        if "Apple Worldwide Developer Relations Certification Authority" in each:
            return True
    Log("加载AppleWWDRCA")
    base = tempfile.gettempdir()
    _shell_run(
        "curl -sSLk https://developer.apple.com/certificationauthority/AppleWWDRCA.cer -o %s/AppleWWDRCA.cer"
        % base)
    _shell_run("security add-certificates %s/AppleWWDRCA.cer" % base)
    return True
Exemple #23
0
def _newbee(_project: IosProjectInfo):
    # 默认一天的时效
    for _ in range(100):
        import uuid
        _uuid = uuid.uuid4()
        if db_session.set("uuid:%s" % _uuid,
                          json_str({
                              "project": _project.project,
                          }),
                          ex=3600 * 24,
                          nx=True):
            Log("生成[%s]一个新的uuid[%s]" % (_project.project, _uuid))
            return str(_uuid)

    raise Fail("生成失败")
Exemple #24
0
def _reg_cert(_config: IosAccountInfo, cert_req_id, name, cert_id, sn,
              type_str, expire):
    sid = "%s:%s" % (_config.account, cert_id)
    _info = IosCertInfo()
    _info.sid = sid
    _info.account = _config.account
    _info.cert_req_id = cert_req_id
    _info.cert_id = cert_id
    _info.sn = sn
    _info.type_str = type_str
    _info.name = name
    _info.create = now()
    _info.expire = datetime.datetime.utcfromtimestamp(expire // 1000)
    _info.save()
    Log("更新证书[%s][%s]" % (name, cert_req_id))
    return cert_req_id
Exemple #25
0
def __list_all_profile(_config: IosAccountHelper, target_project: str = ""):
    ret = _config.post(
        "更新列表",
        "https://developer.apple.com/services-account/QH65B2/account/ios/profile/listProvisioningProfiles.action?teamId=",
        data={
            "includeInactiveProfiles": True,
            "onlyCountLists": True,
            "sidx": "name",
            "sort": "name%3dasc",
            "teamId": _config.team_id,
            "pageNumber": 1,
            "pageSize": 500,
        })
    target = None
    for profile in ret["provisioningProfiles"]:
        if not profile["name"].startswith("专用 "):
            continue
        project = profile["name"].replace("专用 ", "")
        _info = IosProfileInfo.objects.filter(
            sid="%s:%s" %
            (_config.account, project)).first()  # type: IosProfileInfo
        expire = _to_dt(profile["dateExpire"])
        detail = False
        if not _info:
            _info = IosProfileInfo()
            _info.sid = "%s:%s" % (_config.account, project)
            _info.app = _config.account
            _info.profile_id = profile["provisioningProfileId"]
            _info.expire = expire
            _info.devices = ""
            _info.devices_num = 0
            detail = True

        if _info.expire != expire:
            _info.profile_id = profile["provisioningProfileId"]
            _info.expire = expire
            detail = True

        if detail:
            # 获取细节
            __profile_detail(_config, _info)
            Log("更新profile[%s]" % _info.sid)
            _info.save()
        if project == target_project:
            target = _info
    return ret, target
Exemple #26
0
def login_by_fastlane(_req: HttpRequest, cmd: str = "", account: str = ""):
    """
    通过命令获取会话
    fastlane spaceauth -u [email protected]
    ex.
    export FASTLANE_SESSION='---\n- !ruby/object:HTTP::Cookie\n  name: myacinfo\n  value: DAWTKNV2e32a0823580640561dc9dfd382265048c32c2aa5b04485930b2ada1d1c7eba28dee6c6065c749f708f2a429f8f9f2d0f2f7d2ad629652ca5bc3383c0772d51c6ca34a2f7b09141f7b19c358c2b25d0738079ab1e48a06610228a574342c84ef13349ede1a012c25155e265a17989a3b09631dd953954505153fb7ef71aecfe303530cb684c89e8402cb82d8d4d93c3fc3c1209e334f65f71c7ae0cfdf0349ec757abcb104a591f5bea25ac0f1207004c19645b80ed82fb5cd0d3a740224b2f3aef9e91b049bb63a94ae3c76d027411f077069865209d733617a7a84f54cf7e9488e9b4f0a918d29f184f5ec76d95b5f55def61682f70b7f10fc12dc43d6e380213dd1f702a4f3ccab3ad438cd0f6a87c295e028a12ec410aa3fa689210d040377995914d4d3718b90f85ad5452d5db47ef9ae11c6b3216cf8ab61025adc203b0bf072ce832240c384d83f0f4aaf477a3c7313de4c20c5e32c530ff1ad76aebcd8538ac485a9a46941dfa94ee2f3fb40e38666533326562333665333834343461323366383636666563303166613533303330656361323836MVRYV2\n  domain: apple.com\n  for_domain: true\n  path: "/"\n  secure: true\n  httponly: true\n  expires: \n  max_age: \n  created_at: 2019-03-15 11:55:51.031441000 +08:00\n  accessed_at: 2019-03-15 11:55:51.041509000 +08:00\n- !ruby/object:HTTP::Cookie\n  name: dqsid\n  value: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJzZnp2ZGFldGJPeWpXaTc1LVpTRmNBIn0.IEYqXF-pxIYdIwP2rdNRNhoxdCzJgGxt4olTZa2fXo8\n  domain: olympus.itunes.apple.com\n  for_domain: false\n  path: "/"\n  secure: true\n  httponly: true\n  expires: \n  max_age: 1800\n  created_at: &1 2019-03-15 11:55:52.798977000 +08:00\n  accessed_at: *1\n
    curl localhost:8000/apple/login_by_fastlane --data $FASTLANE_SESSION
    """
    if not cmd:
        cmd = _req.body.decode("utf-8")
    Assert(len(cmd), "命令行不对")
    cmd = cmd.replace("\\n", "")
    cookie = dict(re.compile(r"name:\s+(\S+)\s+value:\s+(\S+)").findall(cmd))
    if not account:
        rsp = requests.post(
            "https://developer.apple.com/services-account/QH65B2/account/getUserProfile",
            headers={"cookie": to_form_url(cookie, split=';')})
        if rsp.status_code != 200:
            return {
                "succ": False,
                "reason": "无效的fastlane export",
            }
        data = rsp.json()
        account = data["userProfile"]["email"]

    if account:
        _info = IosAccountInfo.objects.filter(
            account=account).first()  # type:IosAccountInfo
        if not _info:
            _info = IosAccountInfo()
            _info.account = account
            _info.save()
        _info.cookie = json_str(cookie)
        _info.headers = json_str({})
        _info.save()
        Log("通过fastlane登录[%s]" % account)
        return {
            "succ": True,
            "msg": "登录[%s]成功" % account,
        }
    else:
        return {
            "succ": False,
            "msg": "请求不具备提取登录信息",
        }
Exemple #27
0
def __download_profile(_config: IosAccountHelper, _profile: IosProfileInfo):
    ret = _config.post(
        "获取profile文件",
        "https://developer.apple.com/services-account/QH65B2/account/ios/profile/downloadProfileContent?teamId=",
        data={
            "provisioningProfileId": _profile.profile_id,
        },
        json_api=False,
        is_json=False,
        log=False,
        is_binary=True,
        method="GET",
    )
    profile = base64(ret)
    if profile != _profile.profile:
        _profile.profile = base64(ret)
        _profile.save()
        Log("更新profile文件[%s]" % _profile.sid)
Exemple #28
0
def _package(orig_file, provisioning_profile, certificate, output_path):
    base = tempfile.mkdtemp()
    ipa_file = os.path.join(base, "orig.ipa")
    mp_file = os.path.join(base, "mp.ipa")
    os.symlink(os.path.abspath(orig_file), ipa_file)
    os.symlink(os.path.abspath(provisioning_profile), mp_file)
    Log("准备ipa[%s]" % ipa_file)
    # with Block("打包", fail=False):
    #     app = app_argument(ipa_file).unpack_to_dir(base)
    #     Log("准备provision")
    #     app.provision(mp_file)
    #     Log("构造entitlements")
    #     app.create_entitlements()
    #     Log("签名证书")
    #     app.sign(certificate)
    #     Log("重新封包")
    #     app.package(output_path)
    #     Log("ipa[%s]" % output_path)
    try:
        if not os.path.isfile(output_path) or True:
            # 方案二打包
            sh_file = os.path.join(base, "provisions.sh")
            if os.path.exists("provisions.sh"):
                os.symlink(os.path.abspath("provisions.sh"), sh_file)
            else:
                os.symlink(os.path.abspath("tools/provisions.sh"), sh_file)
            _shell_run("%s -p %s -c '%s' %s " %
                       (sh_file, mp_file, certificate, ipa_file),
                       succ_only=True,
                       verbose=True,
                       debug=True,
                       pwd=base)
            Assert(os.path.isfile(os.path.join(base, "stage", "out.ipa")),
                   "打包脚本失败了")
            os.rename(os.path.join(base, "stage", "out.ipa"),
                      os.path.abspath(output_path))

        if not os.path.isfile(output_path):
            raise Fail("打包失败")
    finally:
        shutil.rmtree(base, ignore_errors=True)
Exemple #29
0
def _reg_device(account: str, device_id: str, udid: str, model: str,
                sn: str) -> str:
    # 需要缓存
    _info = IosDeviceInfo()
    _info.sid = "%s:%s" % (account, udid)
    _info.account = account
    _info.udid = udid
    _info.device_id = device_id
    _info.model = model
    _info.sn = sn
    _info.create = now()
    _info.save()
    Log("注册新的设备[%s][%s][%s]" % (udid, device_id, sn))
    _account = IosAccountInfo.objects.get(account=account)
    device_map = str_json(_account.devices)
    device_map[udid] = device_id
    if json_str(device_map) != _account.devices:
        _account.devices = json_str(device_map)
        _account.devices_num = len(device_map)
        _account.save()
    return udid
Exemple #30
0
def upload_ipa(worker: str, uuid: str, file: bytes):
    _user = UserInfo.objects.get(uuid=uuid)
    project = _user.project
    account = _user.account
    base = os.path.join("static/income", project)
    os.makedirs(base, exist_ok=True)
    _info = IosAccountInfo.objects.filter(
        account=account).first()  # type:IosAccountInfo
    Assert(_info, "账号[%s]不存在" % account)
    filename = "%s_%s.ipa" % (_info.team_id, _info.devices_num)
    with open(os.path.join(base, filename), mode="wb") as fout:
        fout.write(file)
    Log("[%s]收到新打包的ipa[%s]" % (account, filename))
    # todo: 遍历所有的设备关联的包?
    _task, _ = TaskInfo.objects.get_or_create(uuid=uuid)
    if _task.worker in {worker, "none"}:
        _task.state = "succ"
        _task.worker = worker
        _task.size = len(file)
        _task.save()
    return {
        "succ": True,
    }