Пример #1
0
    def _get_auth_data(self, record=None, username=None, password=None):
        from tapiriik.auth.credential_storage import CredentialStore

        if record:
            #  longing for C style overloads...
            password = CredentialStore.Decrypt(
                record.ExtendedAuthorization["Password"])
            username = CredentialStore.Decrypt(
                record.ExtendedAuthorization["Email"])

        session = self._get_session(record, username)
        request_parameters = {
            "user[email]": username,
            "user[password]": password
        }
        res = session.post(self._loginUrlRoot, data=request_parameters)

        if res.status_code != 200:
            raise APIException(
                "Login exception {} - {}".format(res.status_code, res.text),
                user_exception=UserException(UserExceptionType.Authorization))

        res_xml = etree.fromstring(res.text.encode('utf-8'))

        info = res_xml.find("info")
        if info.get("status") != "ok":
            raise APIException(info.get("description"),
                               user_exception=UserException(
                                   UserExceptionType.Authorization))

        user_id = int(res_xml.find("user/id").get("value"))
        user_token = res_xml.find("user/authentication_token").get("value")

        return user_id, user_token
Пример #2
0
    def _get_session(self,
                     username=None,
                     password=None,
                     record=None,
                     cookieAuth=False):
        from tapiriik.auth.credential_storage import CredentialStore
        if record:
            password = CredentialStore.Decrypt(
                record.ExtendedAuthorization["Password"])
            username = CredentialStore.Decrypt(
                record.ExtendedAuthorization["Username"])

        session = requests.Session()

        if cookieAuth:
            login_res = session.post(
                "https://www.trainerroad.com/login",
                cookies={"__RequestVerificationToken": "whee"},
                data={
                    "Username": username,
                    "Password": password,
                    "__RequestVerificationToken": "whee"
                },
                allow_redirects=False)
            if login_res.status_code != 302:
                raise APIException("Invalid login %s - %s" %
                                   (login_res.status_code, login_res.text),
                                   block=True,
                                   user_exception=UserException(
                                       UserExceptionType.Authorization,
                                       intervention_required=True))
        else:
            session.auth = (username, password)

        return session
Пример #3
0
 def _authData(self, serviceRecord):
     from tapiriik.auth.credential_storage import CredentialStore
     password = CredentialStore.Decrypt(
         serviceRecord.ExtendedAuthorization["Password"])
     username = CredentialStore.Decrypt(
         serviceRecord.ExtendedAuthorization["Username"])
     return {"username": username, "password": password}
Пример #4
0
    def Authorize(self, email, password):
        from tapiriik.auth.credential_storage import CredentialStore
        params = {
            "email": email,
            "password": password,
            "v": "2.4",
            "action": "pair",
            "deviceId": "TAP-SYNC-" + email.lower(),
            "country": "N/A"
        }  # note to future self: deviceId can't change intra-account otherwise we'll get different tokens back

        resp = requests.get("https://api.mobile.endomondo.com/mobile/auth",
                            params=params)
        if resp.text.strip() == "USER_UNKNOWN" or resp.text.strip(
        ) == "USER_EXISTS_PASSWORD_WRONG":
            raise APIException("Invalid login",
                               block=True,
                               user_exception=UserException(
                                   UserExceptionType.Authorization,
                                   intervention_required=True))
        data = self._parseKVP(resp.text)

        return (data["userId"], {
            "AuthToken": data["authToken"],
            "SecureToken": data["secureToken"]
        }, {
            "Email": CredentialStore.Encrypt(email),
            "Password": CredentialStore.Encrypt(password)
        })
Пример #5
0
 def _get_web_cookies(self, record=None, email=None, password=None):
     from tapiriik.auth.credential_storage import CredentialStore
     if record:
         cached = self._sessionCache.Get(record.ExternalID)
         if cached:
             return cached
         password = CredentialStore.Decrypt(
             record.ExtendedAuthorization["Password"])
         email = CredentialStore.Decrypt(
             record.ExtendedAuthorization["Email"])
     params = {"email": email, "password": password}
     resp = requests.post(
         "https://www.endomondo.com/access?wicket:interface=:1:pageContainer:lowerSection:lowerMain:lowerMainContent:signInPanel:signInFormPanel:signInForm::IFormSubmitListener::",
         data=params,
         allow_redirects=False)
     if resp.status_code >= 500 and resp.status_code < 600:
         raise APIException("Remote API failure")
     if resp.status_code != 302:  # yep
         raise APIException("Invalid login",
                            block=True,
                            user_exception=UserException(
                                UserExceptionType.Authorization,
                                intervention_required=True))
     if record:
         self._sessionCache.Set(record.ExternalID, resp.cookies)
     return resp.cookies
Пример #6
0
 def Authorize(self, email, password):
     from tapiriik.auth.credential_storage import CredentialStore
     resp = requests.post(
         "https://www.trainingpeaks.com/tpwebservices/service.asmx/AuthenticateAccount",
         data={
             "username": email,
             "password": password
         })
     if resp.status_code != 200:
         raise APIException("Invalid login")
     sess_guid = etree.XML(resp.content).text
     cookies = {"mySession_Production": sess_guid}
     resp = requests.get(
         "https://www.trainingpeaks.com/m/Shared/PersonInfo.js",
         cookies=cookies)
     accountIsPremium = re.search(
         "currentAthlete\.IsBasicUser\s*=\s*(true|false);",
         resp.text).group(1) == "false"
     personId = re.search("currentAthlete\.PersonId\s*=\s*(\d+);",
                          resp.text).group(1)
     # Yes, I have it on good authority that this is checked further on on the remote end.
     if not accountIsPremium:
         raise APIException("Account not premium",
                            block=True,
                            user_exception=UserException(
                                UserExceptionType.AccountUnpaid,
                                intervention_required=True,
                                extra=personId))
     return (personId, {}, {
         "Username": CredentialStore.Encrypt(email),
         "Password": CredentialStore.Encrypt(password)
     })
Пример #7
0
 def Authorize(self, email, password):
     from tapiriik.auth.credential_storage import CredentialStore
     cookies = self._get_cookies(email=email, password=password)
     username = requests.get("http://connect.garmin.com/user/username", cookies=cookies).json()["username"]
     if not len(username):
         raise APIException("Unable to retrieve username", block=True, user_exception=UserException(UserExceptionType.Authorization, intervention_required=True))
     return (username, {}, {"Email": CredentialStore.Encrypt(email), "Password": CredentialStore.Encrypt(password)})
Пример #8
0
    def Authorize(self, email, password):
        """
        POST Username and Password

        URL: https://app.velohero.com/sso
        Parameters:
        user = username
        pass = password
        view = json

        The login was successful if you get HTTP status code 200.
        For other HTTP status codes, the login was not successful.
        """

        from tapiriik.auth.credential_storage import CredentialStore

        res = requests.post(self._urlRoot + "/sso",
                            headers=self._obligatory_headers,
                            params={'user': email, 'pass': password, 'view': 'json'})

        if res.status_code != 200:
            raise APIException("Invalid login", block=True, user_exception=UserException(UserExceptionType.Authorization, intervention_required=True))

        res.raise_for_status()
        res = res.json()
        if res["session"] is None:
            raise APIException("Invalid login", block=True, user_exception=UserException(UserExceptionType.Authorization, intervention_required=True))
        member_id = res["user-id"]
        if not member_id:
            raise APIException("Unable to retrieve user id", block=True, user_exception=UserException(UserExceptionType.Authorization, intervention_required=True))
        return (member_id, {}, {"Email": CredentialStore.Encrypt(email), "Password": CredentialStore.Encrypt(password)})
Пример #9
0
 def Authorize(self, email, password):
     from tapiriik.auth.credential_storage import CredentialStore
     res = requests.get("https://ridewithgps.com/users/current.json",
                        params={
                            'email': email,
                            'password': password,
                            'apikey': RWGPS_APIKEY
                        })
     res.raise_for_status()
     res = res.json()
     if res["user"] is None:
         raise APIException("Invalid login",
                            block=True,
                            user_exception=UserException(
                                UserExceptionType.Authorization,
                                intervention_required=True))
     member_id = res["user"]["id"]
     if not member_id:
         raise APIException("Unable to retrieve id",
                            block=True,
                            user_exception=UserException(
                                UserExceptionType.Authorization,
                                intervention_required=True))
     return (member_id, {}, {
         "Email": CredentialStore.Encrypt(email),
         "Password": CredentialStore.Encrypt(password)
     })
Пример #10
0
    def _get_cookies_and_uid(self, record=None, email=None, password=None):
        from tapiriik.auth.credential_storage import CredentialStore
        if record:
            cached = self._sessionCache.Get(record.ExternalID)
            if cached:
                return cached
            password = CredentialStore.Decrypt(
                record.ExtendedAuthorization["Password"])
            email = CredentialStore.Decrypt(
                record.ExtendedAuthorization["Email"])
        params = {"username": email, "password": password}
        resp = requests.post(self.OpenFitEndpoint + "/user/login",
                             data=json.dumps(params),
                             allow_redirects=False,
                             headers={
                                 "Accept": "application/json",
                                 "Content-Type": "application/json"
                             })
        if resp.status_code != 200:
            raise APIException("Invalid login",
                               block=True,
                               user_exception=UserException(
                                   UserExceptionType.Authorization,
                                   intervention_required=True))

        retval = (resp.cookies, int(resp.json()["user"]["uid"]))
        if record:
            self._sessionCache.Set(record.ExternalID, retval)
        return retval
Пример #11
0
 def Authorize(self, email, password):
     from tapiriik.auth.credential_storage import CredentialStore
     cookies, uid = self._get_cookies_and_uid(email=email,
                                              password=password)
     return (uid, {}, {
         "Email": CredentialStore.Encrypt(email),
         "Password": CredentialStore.Encrypt(password)
     })
Пример #12
0
 def Authorize(self, email, password):
     from tapiriik.auth.credential_storage import CredentialStore
     session = self._get_session(email=email, password=password, skip_cache=True)
     # TODO: http://connect.garmin.com/proxy/userprofile-service/socialProfile/ has the proper immutable user ID, not that anyone ever changes this one...
     self._rate_limit()
     username = session.get("http://connect.garmin.com/user/username").json()["username"]
     if not len(username):
         raise APIException("Unable to retrieve username", block=True, user_exception=UserException(UserExceptionType.Authorization, intervention_required=True))
     return (username, {}, {"Email": CredentialStore.Encrypt(email), "Password": CredentialStore.Encrypt(password)})
Пример #13
0
    def _get_session(self,
                     record=None,
                     username=None,
                     password=None,
                     skip_cache=False):
        from tapiriik.auth.credential_storage import CredentialStore
        cached = self._sessionCache.Get(
            record.ExternalID if record else username)
        if cached and not skip_cache:
            logger.debug("Using cached credential")
            return cached
        if record:
            #  longing for C style overloads...
            password = CredentialStore.Decrypt(
                record.ExtendedAuthorization["Password"])
            username = CredentialStore.Decrypt(
                record.ExtendedAuthorization["Email"])

        session = requests.Session()

        data = {"username": username, "password": password}
        params = {
            "response_type": "code",
            "client_id": "ppt_client_id",
            "redirect_uri": "https://polarpersonaltrainer.com/oauth.ftl",
            "scope": "POLAR_SSO"
        }

        preResp = session.get("https://auth.polar.com/oauth/authorize",
                              params=params)
        if preResp.status_code != 200:
            raise APIException("SSO prestart error {} {}".format(
                preResp.status_code, preResp.text))

        # Extract csrf token
        bs = BeautifulSoup(preResp.text, "html.parser")
        csrftoken = bs.find("input", {"name": "_csrf"})["value"]
        data.update({"_csrf": csrftoken})
        ssoResp = session.post("https://auth.polar.com/login", data=data)
        if ssoResp.status_code != 200 or "temporarily unavailable" in ssoResp.text:
            raise APIException("SSO error {} {}".format(
                ssoResp.status_code, ssoResp.text))

        if "error" in ssoResp.url:
            raise APIException("Login exception {}".format(ssoResp.url),
                               user_exception=UserException(
                                   UserExceptionType.Authorization))

        # Finish auth process passing timezone
        session.get(ssoResp.url, params={"userTimezone": "-180"})

        session.get("https://polarpersonaltrainer.com/user/index.ftl")

        self._sessionCache.Set(record.ExternalID if record else username,
                               session)

        return session
Пример #14
0
    def Authorize(self, username, password):
        from tapiriik.auth.credential_storage import CredentialStore
        self._get_session(username=username,
                          password=password,
                          skip_cache=True)

        return (username, {}, {
            "Email": CredentialStore.Encrypt(username),
            "Password": CredentialStore.Encrypt(password)
        })
Пример #15
0
    def Authorize(self, username, password):
        from tapiriik.auth.credential_storage import CredentialStore
        user_id, user_token = self._get_auth_data(username=username, password=password)

        secret = {
            "Email": CredentialStore.Encrypt(username), 
            "Password": CredentialStore.Encrypt(password)
            }
        authorizationData = {"OAuthToken": user_token}
        
        return (user_id, authorizationData, secret)
Пример #16
0
    def _get_session(self,
                     record=None,
                     email=None,
                     password=None,
                     skip_cache=False):
        from tapiriik.auth.credential_storage import CredentialStore
        cached = self._sessionCache.Get(record.ExternalID if record else email)
        if cached and not skip_cache:
            return cached
        if record:
            password = CredentialStore.Decrypt(
                record.ExtendedAuthorization["Password"])
            email = CredentialStore.Decrypt(
                record.ExtendedAuthorization["Email"])

        # This is the most pleasent login flow I've dealt with in a long time
        session = requests.Session()
        session.headers.update(self._obligatoryHeaders)
        session.cookies.update(self._obligatoryCookies)

        res = session.post("https://api.nike.com/nsl/user/login",
                           params={
                               "format": "json",
                               "app": "app",
                               "client_id": NIKEPLUS_CLIENT_ID,
                               "client_secret": NIKEPLUS_CLIENT_SECRET
                           },
                           data={
                               "email": email,
                               "password": password
                           },
                           headers={"Accept": "application/json"})

        if res.status_code >= 500 and res.status_code < 600:
            raise APIException("Login exception %s - %s" %
                               (res.status_code, res.text))

        res_obj = res.json()

        if "access_token" not in res_obj:
            raise APIException("Invalid login %s - %s / %s" %
                               (res.status_code, res.text, res.cookies),
                               block=True,
                               user_exception=UserException(
                                   UserExceptionType.Authorization,
                                   intervention_required=True))

        # Was getting a super obscure error from the nether regions of requestse about duplicate cookies
        # So, store this in an easier-to-find location
        session.access_token = res_obj["access_token"]

        self._sessionCache.Set(record.ExternalID if record else email, session)

        return session
Пример #17
0
 def Authorize(self, email, password):
     from tapiriik.auth.credential_storage import CredentialStore
     session = self._get_session(email=email, password=password, skip_cache=True)
     self._rate_limit()
     try:
         dashboard = session.get("http://connect.garmin.com/modern")
         userdata_json_str = re.search(r"VIEWER_SOCIAL_PROFILE\s*=\s*JSON\.parse\((.+)\);$", dashboard.text, re.MULTILINE).group(1)
         userdata = json.loads(json.loads(userdata_json_str))
         username = userdata["displayName"]
     except Exception as e:
         raise APIException("Unable to retrieve username: %s" % e, block=True, user_exception=UserException(UserExceptionType.Authorization, intervention_required=True))
     return (username, {}, {"Email": CredentialStore.Encrypt(email), "Password": CredentialStore.Encrypt(password)})
Пример #18
0
    def Authorize(self, email, password):
        from tapiriik.auth.credential_storage import CredentialStore
        session = self._get_session(email=email, password=password)

        user_data = session.get("https://api.nike.com/nsl/user/get",
                                params=self._with_auth(session,
                                                       {"format": "json"}))
        user_id = int(
            user_data.json()["serviceResponse"]["body"]["User"]["id"])

        return (user_id, {}, {
            "Email": CredentialStore.Encrypt(email),
            "Password": CredentialStore.Encrypt(password)
        })
Пример #19
0
 def Authorize(self, email, password):
     from tapiriik.auth.credential_storage import CredentialStore
     session = self._get_session(email=email, password=password)
     self._rate_limit()
     id = session.get(self._urlRoot + "/api/tapiriikProfile").json()["id"]
     if not len(id):
         raise APIException("Unable to retrieve username",
                            block=True,
                            user_exception=UserException(
                                UserExceptionType.Authorization,
                                intervention_required=True))
     return (id, {}, {
         "Email": CredentialStore.Encrypt(email),
         "Password": CredentialStore.Encrypt(password)
     })
Пример #20
0
    def EnsureServiceRecordWithAuth(service, uid, authDetails, extendedAuthDetails=None, persistExtendedAuthDetails=False):
        from tapiriik.auth.credential_storage import CredentialStore
        if persistExtendedAuthDetails and not service.RequiresExtendedAuthorizationDetails:
            raise ValueError("Attempting to persist extended auth details on service that doesn't use them")
        # think this entire block could be replaced with an upsert...

        serviceRecord = ServiceRecord(db.connections.find_one({"ExternalID": uid, "Service": service.ID}))
        # Coming out of CredentialStorage these are objects that can't be stuffed into mongodb right away
        # Should really figure out how to mangle pymongo into doing the serialization for me...
        extendedAuthDetailsForStorage = CredentialStore.FlattenShadowedCredentials(extendedAuthDetails) if extendedAuthDetails else None
        if serviceRecord is None:
            db.connections.insert({"ExternalID": uid, "Service": service.ID, "SynchronizedActivities": [], "Authorization": authDetails, "ExtendedAuthorization": extendedAuthDetailsForStorage if persistExtendedAuthDetails else None})
            serviceRecord = ServiceRecord(db.connections.find_one({"ExternalID": uid, "Service": service.ID}))
            serviceRecord.ExtendedAuthorization = extendedAuthDetails # So SubscribeToPartialSyncTrigger can use it (we don't save the whole record after this point)
            if service.PartialSyncTriggerRequiresPolling:
                service.SubscribeToPartialSyncTrigger(serviceRecord) # The subscription is attached more to the remote account than to the local one, so we subscribe/unsubscribe here rather than in User.ConnectService, etc.
        elif serviceRecord.Authorization != authDetails or (hasattr(serviceRecord, "ExtendedAuthorization") and serviceRecord.ExtendedAuthorization != extendedAuthDetailsForStorage):
            db.connections.update({"ExternalID": uid, "Service": service.ID}, {"$set": {"Authorization": authDetails, "ExtendedAuthorization": extendedAuthDetailsForStorage if persistExtendedAuthDetails else None}})

        # if not persisted, these details are stored in the cache db so they don't get backed up
        if service.RequiresExtendedAuthorizationDetails:
            if not persistExtendedAuthDetails:
                cachedb.extendedAuthDetails.update({"ID": serviceRecord._id}, {"ID": serviceRecord._id, "ExtendedAuthorization": extendedAuthDetailsForStorage}, upsert=True)
            else:
                cachedb.extendedAuthDetails.remove({"ID": serviceRecord._id})
        return serviceRecord
Пример #21
0
    def _add_auth_params(self, params=None, record=None):
        """
        Adds username and password to the passed-in params,
        returns modified params dict.
        """

        from tapiriik.auth.credential_storage import CredentialStore

        if params is None:
            params = {}
        if record:
            email = CredentialStore.Decrypt(record.ExtendedAuthorization["Email"])
            password = CredentialStore.Decrypt(record.ExtendedAuthorization["Password"])
            params['user'] = email
            params['pass'] = password
        return params
 def _getUserToken(self, serviceRecord):
     userToken = None
     if serviceRecord:
         from tapiriik.auth.credential_storage import CredentialStore
         userToken = CredentialStore.Decrypt(
             serviceRecord.ExtendedAuthorization["UserToken"])
     return userToken
Пример #23
0
 def _add_auth_params(self, params=None, record=None):
     """
     Adds apikey and authorization (email/password) to the passed-in params,
     returns modified params dict.
     """
     from tapiriik.auth.credential_storage import CredentialStore
     if params is None:
         params = {}
     params['apikey'] = RWGPS_APIKEY
     if record:
         cached = self._sessionCache.Get(record.ExternalID)
         if cached:
             return cached
         password = CredentialStore.Decrypt(record.ExtendedAuthorization["Password"])
         email = CredentialStore.Decrypt(record.ExtendedAuthorization["Email"])
         params['email'] = email
         params['password'] = password
     return params
Пример #24
0
 def _get_cookies(self, record=None, email=None, password=None):
     from tapiriik.auth.credential_storage import CredentialStore
     if record:
         cached = self._sessionCache.Get(record.ExternalID)
         if cached:
             return cached
         #  longing for C style overloads...
         password = CredentialStore.Decrypt(record.ExtendedAuthorization["Password"])
         email = CredentialStore.Decrypt(record.ExtendedAuthorization["Email"])
     params = {"login": "******", "login:loginUsernameField": email, "login:password": password, "login:signInButton": "Sign In", "javax.faces.ViewState": "j_id1"}
     preResp = requests.get("https://connect.garmin.com/signin")
     resp = requests.post("https://connect.garmin.com/signin", data=params, allow_redirects=False, cookies=preResp.cookies)
     if resp.status_code >= 500 and resp.status_code<600:
         raise APIException("Remote API failure")
     if resp.status_code != 302:  # yep
         raise APIException("Invalid login", block=True, user_exception=UserException(UserExceptionType.Authorization, intervention_required=True))
     if record:
         self._sessionCache.Set(record.ExternalID, preResp.cookies)
     return preResp.cookies
Пример #25
0
    def Authorize(self, email, password):
        from tapiriik.auth.credential_storage import CredentialStore
        data = {
            "user[email]": email,
            "user[password]": password,
            "authenticity_token": ""
        }

        resp = requests.post(
            "https://www.runtastic.com/en/d/users/sign_in.json", data=data)
        # TODO Check success atribute of api return, motivato service looks like our service
        # TODO Save session and cookie
        if resp.status_code != 200:
            raise APIException("Invalid login")

        user_id = resp.json()["current_user"]["id"]

        return (user_id, {}, {
            "Email": CredentialStore.Encrypt(email),
            "Password": CredentialStore.Encrypt(password)
        })
Пример #26
0
    def Authorize(self, username, password):
        from tapiriik.auth.credential_storage import CredentialStore
        session = self._get_session(username, password)
        session.headers.update({"Accept": "application/json"})
        user_resp = session.get("https://api.trainerroad.com/api/members")

        if user_resp.status_code != 200:
            if user_resp.status_code == 401:
                raise APIException("Invalid login",
                                   block=True,
                                   user_exception=UserException(
                                       UserExceptionType.Authorization,
                                       intervention_required=True))
            raise APIException("Login error")

        member_id = int(user_resp.json()["MemberId"])

        return (member_id, {}, {
            "Username": CredentialStore.Encrypt(username),
            "Password": CredentialStore.Encrypt(password)
        })
Пример #27
0
    def Authorize(self, email, password):
        from tapiriik.auth.credential_storage import CredentialStore

        soap_auth_data = {"username": email, "password": password}

        resp = requests.post(
            "https://www.trainingpeaks.com/tpwebservices/service.asmx/AuthenticateAccount",
            data=soap_auth_data)
        if resp.status_code != 200:
            raise APIException("Invalid login")

        soap_auth_data.update({
            "types":
            "CoachedPremium,SelfCoachedPremium,SharedCoachedPremium,CoachedFree,SharedFree,Plan"
        })
        users_resp = requests.post(
            "https://www.trainingpeaks.com/tpwebservices/service.asmx/GetAccessibleAthletes",
            data=soap_auth_data)
        users_resp = etree.XML(users_resp.content)

        personId = None
        for xperson in users_resp:
            xpersonid = xperson.find("tpw:PersonId", namespaces=self._tp_ns)
            if xpersonid is not None and xpersonid.text:
                personId = int(xpersonid.text)
                break

        # Yes, I have it on good authority that this is checked further on on the remote end.
        if not personId:
            raise APIException("Account not premium",
                               block=True,
                               user_exception=UserException(
                                   UserExceptionType.AccountUnpaid,
                                   intervention_required=True,
                                   extra=personId))
        return (personId, {}, {
            "Username": CredentialStore.Encrypt(email),
            "Password": CredentialStore.Encrypt(password)
        })
    def Authorize(self, username, password):
        session = self._prepare_request()
        requestParameters = {"username": username, "password": password}
        user_resp = session.get(self._loginUrlRoot, params=requestParameters)

        if user_resp.status_code != 200:
            raise APIException("Login error")

        response = user_resp.json()

        if response["LoginResponseCode"] == 3:
            from tapiriik.auth.credential_storage import CredentialStore
            member_id = int(response["MemberId"])
            token = response["UserToken"]
            return member_id, {}, {"UserToken": CredentialStore.Encrypt(token)}

        if response["LoginResponseCode"] == 0:
            raise APIException("Invalid API key")

        # Incorrect username or password
        if response["LoginResponseCode"] == -3 or response[
                "LoginResponseCode"] == -2 or response[
                    "LoginResponseCode"] == -1:
            raise APIException("Invalid login - Bad username or password",
                               block=True,
                               user_exception=UserException(
                                   UserExceptionType.Authorization,
                                   intervention_required=True))

        # Account is inactive or locked out - Rarely would happen
        if response["LoginResponseCode"] == 1 or response[
                "LoginResponseCode"] == 2:
            raise APIException("Invalid login - Account is inactive",
                               block=True,
                               user_exception=UserException(
                                   UserExceptionType.Authorization,
                                   intervention_required=True))

        # Something extra unusual has happened
        raise APIException("Invalid login - Unknown error",
                           block=True,
                           user_exception=UserException(
                               UserExceptionType.Authorization,
                               intervention_required=True))
Пример #29
0
    def _get_session(self,
                     record=None,
                     email=None,
                     password=None,
                     skip_cache=False):
        from tapiriik.auth.credential_storage import CredentialStore
        cached = self._sessionCache.Get(record.ExternalID if record else email)
        if cached and not skip_cache:
            logger.debug("Using cached credential")
            return cached
        if record:
            #  longing for C style overloads...
            password = CredentialStore.Decrypt(
                record.ExtendedAuthorization["Password"])
            email = CredentialStore.Decrypt(
                record.ExtendedAuthorization["Email"])

        session = requests.Session()

        # JSIG CAS, cool I guess.
        # Not quite OAuth though, so I'll continue to collect raw credentials.
        # Commented stuff left in case this ever breaks because of missing parameters...
        data = {
            "username": email,
            "password": password,
            "_eventId": "submit",
            "embed": "true",
            # "displayNameRequired": "false"
        }
        params = {
            "service": "https://connect.garmin.com/post-auth/login",
            # "redirectAfterAccountLoginUrl": "http://connect.garmin.com/post-auth/login",
            # "redirectAfterAccountCreationUrl": "http://connect.garmin.com/post-auth/login",
            # "webhost": "olaxpw-connect00.garmin.com",
            "clientId": "GarminConnect",
            # "gauthHost": "https://sso.garmin.com/sso",
            # "rememberMeShown": "true",
            # "rememberMeChecked": "false",
            "consumeServiceTicket": "false",
            # "id": "gauth-widget",
            # "embedWidget": "false",
            # "cssUrl": "https://static.garmincdn.com/com.garmin.connect/ui/src-css/gauth-custom.css",
            # "source": "http://connect.garmin.com/en-US/signin",
            # "createAccountShown": "true",
            # "openCreateAccount": "false",
            # "usernameShown": "true",
            # "displayNameShown": "false",
            # "initialFocus": "true",
            # "locale": "en"
        }
        # I may never understand what motivates people to mangle a perfectly good protocol like HTTP in the ways they do...
        preResp = session.get("https://sso.garmin.com/sso/login",
                              params=params)
        if preResp.status_code != 200:
            raise APIException("SSO prestart error %s %s" %
                               (preResp.status_code, preResp.text))
        data["lt"] = re.search("name=\"lt\"\s+value=\"([^\"]+)\"",
                               preResp.text).groups(1)[0]

        ssoResp = session.post("https://sso.garmin.com/sso/login",
                               params=params,
                               data=data,
                               allow_redirects=False)
        if ssoResp.status_code != 200 or "temporarily unavailable" in ssoResp.text:
            raise APIException("SSO error %s %s" %
                               (ssoResp.status_code, ssoResp.text))

        if "renewPassword" in ssoResp.text:
            raise APIException("Reset password",
                               block=True,
                               user_exception=UserException(
                                   UserExceptionType.RenewPassword,
                                   intervention_required=True))
        ticket_match = re.search("ticket=([^']+)'", ssoResp.text)
        if not ticket_match:
            raise APIException("Invalid login",
                               block=True,
                               user_exception=UserException(
                                   UserExceptionType.Authorization,
                                   intervention_required=True))
        ticket = ticket_match.groups(1)[0]

        # ...AND WE'RE NOT DONE YET!

        self._rate_limit()
        gcRedeemResp = session.get(
            "https://connect.garmin.com/post-auth/login",
            params={"ticket": ticket},
            allow_redirects=False)
        if gcRedeemResp.status_code != 302:
            raise APIException("GC redeem-start error %s %s" %
                               (gcRedeemResp.status_code, gcRedeemResp.text))

        # There are 6 redirects that need to be followed to get the correct cookie
        # ... :(
        expected_redirect_count = 6
        current_redirect_count = 1
        while True:
            self._rate_limit()
            gcRedeemResp = session.get(gcRedeemResp.headers["location"],
                                       allow_redirects=False)

            if current_redirect_count >= expected_redirect_count and gcRedeemResp.status_code != 200:
                raise APIException(
                    "GC redeem %d/%d error %s %s" %
                    (current_redirect_count, expected_redirect_count,
                     gcRedeemResp.status_code, gcRedeemResp.text))
            if gcRedeemResp.status_code == 200 or gcRedeemResp.status_code == 404:
                break
            current_redirect_count += 1
            if current_redirect_count > expected_redirect_count:
                break

        self._sessionCache.Set(record.ExternalID if record else email, session)

        session.headers.update(self._obligatory_headers)

        return session
Пример #30
0
    def _get_session(self,
                     record=None,
                     email=None,
                     password=None,
                     skip_cache=False):
        from tapiriik.auth.credential_storage import CredentialStore
        cached = self._sessionCache.Get(record.ExternalID if record else email)
        if cached and not skip_cache:
            return cached
        if record:
            #  longing for C style overloads...
            password = CredentialStore.Decrypt(
                record.ExtendedAuthorization["Password"])
            email = CredentialStore.Decrypt(
                record.ExtendedAuthorization["Email"])

        session = requests.Session()
        self._rate_limit()
        gcPreResp = session.get("http://connect.garmin.com/",
                                allow_redirects=False)
        # New site gets this redirect, old one does not
        if gcPreResp.status_code == 200:
            self._rate_limit()
            gcPreResp = session.get("https://connect.garmin.com/signin",
                                    allow_redirects=False)
            req_count = int(
                re.search("j_id(\d+)", gcPreResp.text).groups(1)[0])
            params = {
                "login": "******",
                "login:loginUsernameField": email,
                "login:password": password,
                "login:signInButton": "Sign In"
            }
            auth_retries = 3  # Did I mention Garmin Connect is silly?
            for retries in range(auth_retries):
                params["javax.faces.ViewState"] = "j_id%d" % req_count
                req_count += 1
                self._rate_limit()
                resp = session.post("https://connect.garmin.com/signin",
                                    data=params,
                                    allow_redirects=False)
                if resp.status_code >= 500 and resp.status_code < 600:
                    raise APIException("Remote API failure")
                if resp.status_code != 302:  # yep
                    if "errorMessage" in resp.text:
                        if retries < auth_retries - 1:
                            time.sleep(1)
                            continue
                        else:
                            raise APIException(
                                "Invalid login",
                                block=True,
                                user_exception=UserException(
                                    UserExceptionType.Authorization,
                                    intervention_required=True))
                    else:
                        raise APIException("Mystery login error %s" %
                                           resp.text)
                break
        elif gcPreResp.status_code == 302:
            # JSIG CAS, cool I guess.
            # Not quite OAuth though, so I'll continue to collect raw credentials.
            # Commented stuff left in case this ever breaks because of missing parameters...
            data = {
                "username": email,
                "password": password,
                "_eventId": "submit",
                "embed": "true",
                # "displayNameRequired": "false"
            }
            params = {
                "service": "http://connect.garmin.com/post-auth/login",
                # "redirectAfterAccountLoginUrl": "http://connect.garmin.com/post-auth/login",
                # "redirectAfterAccountCreationUrl": "http://connect.garmin.com/post-auth/login",
                # "webhost": "olaxpw-connect00.garmin.com",
                "clientId": "GarminConnect",
                # "gauthHost": "https://sso.garmin.com/sso",
                # "rememberMeShown": "true",
                # "rememberMeChecked": "false",
                "consumeServiceTicket": "false",
                # "id": "gauth-widget",
                # "embedWidget": "false",
                # "cssUrl": "https://static.garmincdn.com/com.garmin.connect/ui/src-css/gauth-custom.css",
                # "source": "http://connect.garmin.com/en-US/signin",
                # "createAccountShown": "true",
                # "openCreateAccount": "false",
                # "usernameShown": "true",
                # "displayNameShown": "false",
                # "initialFocus": "true",
                # "locale": "en"
            }
            # I may never understand what motivates people to mangle a perfectly good protocol like HTTP in the ways they do...
            preResp = session.get("https://sso.garmin.com/sso/login",
                                  params=params)
            if preResp.status_code != 200:
                raise APIException("SSO prestart error %s %s" %
                                   (preResp.status_code, preResp.text))
            data["lt"] = re.search("name=\"lt\"\s+value=\"([^\"]+)\"",
                                   preResp.text).groups(1)[0]

            ssoResp = session.post("https://sso.garmin.com/sso/login",
                                   params=params,
                                   data=data,
                                   allow_redirects=False)
            if ssoResp.status_code != 200:
                raise APIException("SSO error %s %s" %
                                   (ssoResp.status_code, ssoResp.text))

            ticket_match = re.search("ticket=([^']+)'", ssoResp.text)
            if not ticket_match:
                raise APIException("Invalid login",
                                   block=True,
                                   user_exception=UserException(
                                       UserExceptionType.Authorization,
                                       intervention_required=True))
            ticket = ticket_match.groups(1)[0]

            # ...AND WE'RE NOT DONE YET!

            self._rate_limit()
            gcRedeemResp1 = session.get(
                "http://connect.garmin.com/post-auth/login",
                params={"ticket": ticket},
                allow_redirects=False)
            if gcRedeemResp1.status_code != 302:
                raise APIException(
                    "GC redeem 1 error %s %s" %
                    (gcRedeemResp1.status_code, gcRedeemResp1.text))

            self._rate_limit()
            gcRedeemResp2 = session.get(gcRedeemResp1.headers["location"],
                                        allow_redirects=False)
            if gcRedeemResp2.status_code != 302:
                raise APIException(
                    "GC redeem 2 error %s %s" %
                    (gcRedeemResp2.status_code, gcRedeemResp2.text))

        else:
            raise APIException("Unknown GC prestart response %s %s" %
                               (gcPreResp.status_code, gcPreResp.text))

        self._sessionCache.Set(record.ExternalID if record else email, session)

        session.headers.update(self._obligatory_headers)

        return session