コード例 #1
0
ファイル: views.py プロジェクト: doubleC2/ios_ci
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
コード例 #2
0
ファイル: views.py プロジェクト: Maroc-OS/ios_ci
def download_process(
    _req: HttpRequest,
    download_id: str,
    timeout=3000,
    last: int = 0,
):
    if download_id not in __download_process:
        gevent.sleep(timeout / 1000)
        return {
            "code": 0,
            "progress": 0,
            "total": 1,
        }
    else:
        orig = last or __download_process[download_id]
        total = __download_total[download_id]
        if orig == total:
            return {
                "code": 0,
                "progress": total,
                "total": total,
            }
        expire = (now() + timeout) if timeout > 0 else (now() + 30 * 1000)
        while now() < expire:
            if __download_process[download_id] == orig:
                gevent.sleep(1)
            else:
                # 进度有变化就马上回去
                break
        return {
            "code": 0,
            "progress": __download_process[download_id],
            "total": total,
        }
コード例 #3
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)
コード例 #4
0
ファイル: views.py プロジェクト: doubleC2/ios_ci
def wait():
    __pub = db_session.pubsub()
    __pub.subscribe("account:security:code")
    expire = now() + 1200 * 1000
    while now() < expire:
        gevent.sleep(1)
        for data in message_from_topic(__pub, is_json=True, limit=1):
            return data
    raise Fail("超时")
コード例 #5
0
 def acquire(self, timeout=10000, delta=10):
     timeout = self.__timeout or timeout // 1000 or 1000
     if db_session.set(self.__key, 1, ex=timeout, nx=False):
         self.__lock = True
         return
     expire = now() + timeout
     while now() < expire:
         if db_session.set(self.__key, 1, ex=timeout, nx=False):
             self.__lock = True
             return
         gevent.sleep(delta)
     raise Fail("[%s]锁竞争失败" % self.__key)
コード例 #6
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("登录二次验证超时")
コード例 #7
0
ファイル: views.py プロジェクト: doubleC2/ios_ci
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(),
        }))
コード例 #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})
コード例 #9
0
 def is_login(self) -> ExFalse:
     if "myacinfo" not in self.cookie:
         return ExFalse("未登录")
     if int(self.cookie.get("__expire", 0)) < now():
         # 登录信息已经过期需要刷新
         return ExFalse("登录过期")
     if not self.team_id:
         return ExFalse("team_id缺失")
     return ExFalse.TRUE
コード例 #10
0
ファイル: views.py プロジェクト: Maroc-OS/ios_ci
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
コード例 #11
0
ファイル: views.py プロジェクト: doubleC2/ios_ci
def _get_cert(info: IosAccountInfo) -> IosCertInfo:
    cert = IosCertInfo.objects.filter(
        app=info.account,
        expire__gt=datetime.datetime.utcfromtimestamp(now() // 1000),
        type_str="development",
    ).first()  # type: IosCertInfo
    if not cert:
        # todo: 生成证书
        pass
    return Assert(cert, "缺少现成的开发[iOS App Development]证书[%s]" % info.account)
コード例 #12
0
ファイル: views.py プロジェクト: doubleC2/ios_ci
def security_code_sms(phone: str, sms: str):
    Assert("apple" in sms.lower(), "短信非验证码短信[%s]" % sms)
    code = re.compile(r"\d{4,6}").findall(sms)
    Assert(len(code), "短信非验证码短信[%s]" % sms)
    code = code[0]
    _account = IosAccountInfo.objects.filter(
        phone=phone).first()  # type: IosAccountInfo
    publish_security_code(_account.account if _account else "*", code, now())
    return {
        "succ": True,
    }
コード例 #13
0
ファイル: views.py プロジェクト: doubleC2/ios_ci
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
コード例 #14
0
ファイル: views.py プロジェクト: doubleC2/ios_ci
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))
コード例 #15
0
ファイル: views.py プロジェクト: Maroc-OS/ios_ci
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
コード例 #16
0
ファイル: views.py プロジェクト: Maroc-OS/ios_ci
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
コード例 #17
0
ファイル: utils.py プロジェクト: ai966669/ios_ci
 def is_login(self):
     return "myacinfo" in self.cookie and self.team_id and self.cookie and self.info.csrf_ts > now()
コード例 #18
0
    def __login(self):
        if self.csrf_ts > now():
            return
        with Block("账号登录"):
            ret = requests.post(
                "https://developer.apple.com/services-account/QH65B2/account/getTeams",
                json={
                    "includeInMigrationTeams": 1,
                },
                headers={
                    'cookie': to_form_url(self.cookie, split=';'),
                },
                timeout=3,
                verify=False).json() if not self.team_id else {}
            if ret.get("resultCode") == 0:
                self.teams = list(map(lambda x: x["teamId"], ret["teams"]))
                self.info.team_id = self.team_id = self.teams[0]
                self.info.teams = json_str(self.teams)
                self.info.save()
            else:
                # 重新登录
                self.session = requests.session()
                self.session.headers["User-Agent"] = "Spaceship 2.117.1"

                rsp = self.session.get(
                    "https://olympus.itunes.apple.com/v1/app/config?hostname=itunesconnect.apple.com"
                ).json()
                self.session.headers["X-Apple-Widget-Key"] = rsp[
                    "authServiceKey"]
                # self.session.headers["X-Apple-Widget-Key"] = "16452abf721961a1728885bef033f28e"
                self.session.headers["Accept"] = "application/json"
                rsp = self.session.post(
                    "https://idmsa.apple.com/appleauth/auth/signin",
                    json={
                        "accountName": self.account,
                        "password": self.password,
                        "rememberMe": True,
                    },
                    timeout=3)
                self.session.headers["x-apple-id-session-id"] = rsp.headers[
                    "x-apple-id-session-id"]
                self.session.headers["scnt"] = rsp.headers["scnt"]
                if rsp.status_code == 409:
                    # 二次验证
                    # noinspection PyUnusedLocal
                    rsp = self.session.post(
                        "https://idmsa.apple.com/appleauth/auth")
                    # Log("===> https://idmsa.apple.com/appleauth/auth [%s] %s" % (rsp.status_code, rsp.json()))

                    # 切手机验证码
                    rsp = self.session.put(
                        "https://idmsa.apple.com/appleauth/auth/verify/phone",
                        json={
                            "phoneNumber": {
                                "id": 1
                            },
                            "mode": "sms",
                        })
                    Assert(rsp.status_code == 200, "[%s]短信发送失败" % self.account)
                    # Log("===> https://idmsa.apple.com/appleauth/auth/verify/phone [%s] %s" % (rsp.status_code, rsp.json()))
                    _wait_code(self.info, self.session, now())

                self.cookie.update(self.session.cookies)
                self.__expire = now() + 3600 * 1000
        if not self.team_id:
            ret = requests.post(
                "https://developer.apple.com/services-account/QH65B2/account/getTeams",
                json={
                    "includeInMigrationTeams": 1,
                },
                headers={
                    'cookie': to_form_url(self.cookie, split=';'),
                },
                timeout=3,
                verify=False).json()
            if ret["resultCode"] == 0:
                self.teams = list(map(lambda x: x["teamId"], ret["teams"]))
                self.info.team_id = self.team_id = self.teams[0]
                self.info.teams = json_str(self.teams)
                self.info.save()
            else:
                Log("[%s]获取team失败登出了" % self.account)
                self.__logout()
        Log("apple账号[%s:%s]登录完成了" % (self.account, self.team_id))
コード例 #19
0
    def post(self,
             title: str,
             url: str,
             data: Union[Dict, str] = None,
             is_json=True,
             log=True,
             cache: Union[bool, int] = False,
             csrf=False,
             json_api=True,
             method="POST",
             is_binary=False,
             ex_headers=None,
             status=200):
        if cache is True:
            expire = 3600 * 1000
        else:
            expire = cache

        if not self.is_login:
            self.__login()
        start = now()
        rsp_str = "#NODATA#"
        try:
            if "teamId=" in url:
                if "teamId=%s" % self.team_id not in url:
                    url = url.replace("teamId=", "teamId=%s" % self.team_id)
            if cache:
                rsp_str = _cache(url, data) or rsp_str
            headers = {
                'cookie':
                to_form_url({"myacinfo": self.cookie["myacinfo"]}, split=';'),
            }
            if csrf:
                headers.update({
                    'csrf': self.csrf,
                    'csrf_ts': self.csrf_ts,
                })
            if ex_headers:
                headers.update(ex_headers)
            if rsp_str == "#NODATA#":
                if method.upper() == "GET":
                    rsp = requests.get(url,
                                       params=data,
                                       headers=headers,
                                       timeout=3,
                                       verify=False)
                else:
                    rsp = requests.post(url,
                                        data=data,
                                        headers=headers,
                                        timeout=3,
                                        verify=False)

                rsp_str = rsp.text
                if rsp.headers.get("csrf"):
                    self.csrf = rsp.headers["csrf"]
                    self.csrf_ts = int(rsp.headers["csrf_ts"])
                Assert(rsp.status_code == status,
                       "请求[%s]异常[%s]" % (title, rsp.status_code))
                if json_api:
                    _data = str_json_i(rsp_str) or {}
                    if _data.get("resultCode") == 1100:
                        self.__logout()
                        raise Fail("登录[%s]过期了[%s][%s]" %
                                   (self.account, _data.get("resultString"),
                                    _data.get("userString")))
                    Assert(
                        _data.get("resultCode") == 0, "请求业务[%s]失败[%s][%s]" %
                        (title, _data.get("resultString"),
                         _data.get("userString")))
                if log:
                    Log("apple请求[%s][%s]发送[%r]成功[%r]" %
                        (title, now() - start, data, rsp_str))
                if is_binary:
                    rsp_str = base64(rsp.content)
                if cache:
                    _set_cache(url, data, rsp_str, expire=expire)
            if is_json:
                return str_json(rsp_str)
            elif is_binary:
                return base64decode(rsp_str)
            else:
                return rsp_str
        except Exception as e:
            if log:
                Log("apple请求[%s][%s]发送[%r]失败[%r]" %
                    (title, now() - start, data, rsp_str))
            raise e
コード例 #20
0
ファイル: views.py プロジェクト: doubleC2/ios_ci
def security_code(account: str, code: str):
    publish_security_code(account, code, now())
    return {
        "succ": True,
    }
コード例 #21
0
ファイル: tasks.py プロジェクト: ai966669/ios_ci
def _shell_run(cmd: str,
               timeout=30000,
               succ_only=False,
               include_err=True,
               err_last=False,
               pwd=None,
               verbose=False,
               debug=False):
    if debug:
        verbose = True
    if verbose:
        if debug:
            Log("+ [%s] [%s]" % (os.path.abspath(pwd or os.path.curdir), cmd))
        else:
            Log("+ [%s]" % cmd)
    p = Popen(cmd,
              bufsize=1,
              stdout=subprocess.PIPE,
              stderr=subprocess.STDOUT
              if include_err and not err_last else subprocess.PIPE,
              shell=True,
              cwd=pwd)
    expire = now() + timeout
    buffer = []
    buffer_err = []
    while p.poll() is None:
        if now() < expire:
            time.sleep(0.1)
        else:
            p.kill()
            break
        if p.stdout.readable():
            buffer.extend(p.stdout.readlines())
        if include_err:
            if err_last:
                if p.stderr.readable():
                    buffer_err.extend(p.stderr.readlines())

    if succ_only:
        if p.returncode == 0:
            pass
        else:
            raise Fail("命令[%s]执行失败" % cmd)
    if p.stdout and p.stdout.readable():
        buffer.extend(p.stdout.readlines())
    if p.stderr and p.stderr.readable():
        buffer_err.extend(p.stderr.readlines())
    # todo: 采用yield后会导致不执行...
    # if debug:
    #     for each in map(lambda x: x.decode("utf8"), buffer):  # type:str
    #         Log("- %s" % each.rstrip("\r\n"))
    #         yield each.rstrip("\r\n")
    #     if err_last:
    #         for each in map(lambda x: x.decode("utf8"), buffer_err):  # type:str
    #             Log("* %s" % each.rstrip("\r\n"))
    #             yield each.rstrip("\r\n")
    # else:
    #     for each in map(lambda x: x.decode("utf8"), buffer):  # type:str
    #         yield each.rstrip("\r\n")
    #     if err_last:
    #         for each in map(lambda x: x.decode("utf8"), buffer_err):  # type:str
    #             yield each.rstrip("\r\n")
    if debug:
        tmp = []
        for each in map(lambda x: x.decode("utf8"), buffer):  # type:str
            Log("- %s" % each.rstrip("\r\n"))
            tmp.append(each.rstrip("\r\n"))
        if err_last:
            for each in map(lambda x: x.decode("utf8"),
                            buffer_err):  # type:str
                Log("* %s" % each.rstrip("\r\n"))
                tmp.append(each.rstrip("\r\n"))
        return tmp
    else:
        tmp = []
        for each in map(lambda x: x.decode("utf8"), buffer):  # type:str
            tmp.append(each.rstrip("\r\n"))
        if err_last:
            for each in map(lambda x: x.decode("utf8"),
                            buffer_err):  # type:str
                tmp.append(each.rstrip("\r\n"))
        return tmp