Пример #1
0
def test_authorize() -> None:
    """Test function."""
    client_id = "fake_client_id"
    consumer_secret = "fake_consumer_secret"
    callback_uri = "http://127.0.0.1:8080"
    arrow.utcnow = MagicMock(return_value=arrow.get(100000000))

    responses.add(
        method=responses.POST,
        url="https://account.withings.com/oauth2/token",
        json=_FETCH_TOKEN_RESPONSE_BODY,
        status=200,
    )

    auth = WithingsAuth(
        client_id,
        consumer_secret,
        callback_uri=callback_uri,
        scope=(AuthScope.USER_METRICS, AuthScope.USER_ACTIVITY),
    )

    url = auth.get_authorize_url()

    assert url.startswith(
        "https://account.withings.com/oauth2_user/authorize2")

    assert_url_query_equals(
        url,
        {
            "response_type": "code",
            "client_id": "fake_client_id",
            "redirect_uri": "http://127.0.0.1:8080",
            "scope": "user.metrics,user.activity",
        },
    )

    params = dict(parse.parse_qsl(parse.urlsplit(url).query))
    assert "scope" in params
    assert len(params["scope"]) > 0

    creds = auth.get_credentials("FAKE_CODE")

    assert creds == Credentials(
        access_token="my_access_token",
        token_expiry=100000011,
        token_type="Bearer",
        refresh_token="my_refresh_token",
        userid=_USERID,
        client_id=client_id,
        consumer_secret=consumer_secret,
    )
Пример #2
0
    def index(self, reload=None, state=None, code=None, error=None):
        """
        Build index.html for cherrypy

        Render the template and return the html file to be delivered to the browser

        :return: contents of the template after beeing rendered
        """
        if self._auth is None:
            self._auth = WithingsAuth(
                client_id=self.plugin.get_client_id(),
                consumer_secret=self.plugin.get_consumer_secret(),
                callback_uri=self.plugin.get_callback_url(),
                scope=(AuthScope.USER_ACTIVITY,
                       AuthScope.USER_METRICS,
                       AuthScope.USER_INFO,
                       AuthScope.USER_SLEEP_EVENTS,)
            )

        if not reload and code:
            self.logger.debug("Got code as callback: {}".format(self.plugin.get_fullname(), code))
            credentials = None
            try:
                credentials = self._auth.get_credentials(code)
            except Exception as e:
                self.logger.error(
                    "An error occurred, perhaps code parameter is invalid or too old? Message: {}".format(
                        str(e)))
            if credentials is not None:
                self._creds = credentials
                self.logger.debug(
                    "New credentials are: access_token {}, token_expiry {}, token_type {}, refresh_token {}".
                        format(self.plugin.get_fullname(), self._creds.access_token, self._creds.token_expiry,
                               self._creds.token_type, self._creds.refresh_token))
                self.plugin.get_item('access_token')(self._creds.access_token)
                self.plugin.get_item('token_expiry')(self._creds.token_expiry)
                self.plugin.get_item('token_type')(self._creds.token_type)
                self.plugin.get_item('refresh_token')(self._creds.refresh_token)

                self.plugin._client = None

        tmpl = self.tplenv.get_template('index.html')
        return tmpl.render(plugin_shortname=self.plugin.get_shortname(), plugin_version=self.plugin.get_version(),
                           interface=None, item_count=len(self.plugin.get_items()),
                           plugin_info=self.plugin.get_info(), tabcount=2, callback_url=self.plugin.get_callback_url(),
                           tab1title="Withings Health Items (%s)" % len(self.plugin.get_items()),
                           tab2title="OAuth2 Data", authorize_url=self._auth.get_authorize_url(),
                           p=self.plugin, token_expiry=datetime.datetime.fromtimestamp(self.plugin.get_item(
                'token_expiry')(), tz=self.plugin.shtime.tzinfo()), now=self.plugin.shtime.now(), code=code,
                           state=state, reload=reload, language=self.plugin.get_sh().get_defaultlanguage())
Пример #3
0
    def __init__(self):
        self.api = None
        self.scale = Settings.objects.first().default_scale

        self.auth = WithingsAuth(
            client_id=settings.WITHINGS_API_CLIENT_ID,
            consumer_secret=settings.WITHINGS_API_CONSUMER_SECRET,
            callback_uri=settings.WITHINGS_API_CALLBACK_URI,
            scope=(
                AuthScope.USER_ACTIVITY,
                AuthScope.USER_METRICS,
                AuthScope.USER_INFO,
                AuthScope.USER_SLEEP_EVENTS,
            ),
        )
Пример #4
0
def test_get_authorize_url() -> None:
    """Test function."""

    auth1: Final = WithingsAuth(
        client_id="fake_client_id",
        consumer_secret="fake_consumer_secret",
        callback_uri="http://localhost",
    )

    auth2: Final = WithingsAuth(
        client_id="fake_client_id",
        consumer_secret="fake_consumer_secret",
        callback_uri="http://localhost",
        mode="MY_MODE",
    )

    assert "&mode=MY_MODE" not in auth1.get_authorize_url()
    assert "&mode=MY_MODE" in auth2.get_authorize_url()
Пример #5
0
 def __init__(self):
     scope = (
         AuthScope.USER_ACTIVITY,
         AuthScope.USER_METRICS,
         AuthScope.USER_INFO,
         AuthScope.USER_SLEEP_EVENTS,
     )
     client = WithingsAuth(
         client_id=config.withings_client_id,
         consumer_secret=config.withings_consumer_secret,
         callback_uri=config.withings_redirect_uri,
         scope=scope,
     )
     self.client: WithingsAuth = client
Пример #6
0
 def auth_client():
     scope = (
         AuthScope.USER_ACTIVITY,
         AuthScope.USER_METRICS,
         AuthScope.USER_INFO,
         AuthScope.USER_SLEEP_EVENTS,
     )
     client = WithingsAuth(
         client_id=config.withings_client_id,
         consumer_secret=config.withings_consumer_secret,
         callback_uri=config.withings_redirect_uri,
         scope=scope,
     )
     return client
Пример #7
0
def test_authorize() -> None:
    """Test function."""
    client_id: Final = "fake_client_id"
    consumer_secret: Final = "fake_consumer_secret"
    callback_uri: Final = "http://127.0.0.1:8080"

    responses.add(
        method=responses.POST,
        url="https://account.withings.com/oauth2/token",
        json=_FETCH_TOKEN_RESPONSE_BODY,
        status=200,
    )

    auth: Final = WithingsAuth(
        client_id,
        consumer_secret,
        callback_uri=callback_uri,
        scope=(AuthScope.USER_METRICS, AuthScope.USER_ACTIVITY),
    )

    url: Final = auth.get_authorize_url()

    assert url.startswith(
        "https://account.withings.com/oauth2_user/authorize2")

    assert_url_query_equals(
        url,
        {
            "response_type": "code",
            "client_id": "fake_client_id",
            "redirect_uri": "http://127.0.0.1:8080",
            "scope": "user.metrics,user.activity",
        },
    )

    params: Final = dict(parse.parse_qsl(parse.urlsplit(url).query))
    assert "scope" in params
    assert len(params["scope"]) > 0

    creds: Final = auth.get_credentials("FAKE_CODE")

    assert creds.access_token == "my_access_token"
    assert creds.token_type == "Bearer"
    assert creds.refresh_token == "my_refresh_token"
    assert creds.userid == _USERID
    assert creds.client_id == client_id
    assert creds.consumer_secret == consumer_secret
    assert creds.expires_in == 11
    assert creds.token_expiry == arrow.utcnow().int_timestamp + 11
Пример #8
0
def main() -> None:
    """Run main function."""
    parser: Final = argparse.ArgumentParser(
        description="Process some integers.")
    parser.add_argument(
        "--client-id",
        dest="client_id",
        help="Client id provided by withings.",
        required=True,
    )
    parser.add_argument(
        "--consumer-secret",
        dest="consumer_secret",
        help="Consumer secret provided by withings.",
        required=True,
    )
    parser.add_argument(
        "--callback-uri",
        dest="callback_uri",
        help="Callback URI configured for withings application.",
        required=True,
    )
    parser.add_argument(
        "--live-data",
        dest="live_data",
        action="store_true",
        help=
        "Should we run against live data? (Removal of .credentials file is required before running)",
    )

    args: Final = parser.parse_args()

    if path.isfile(CREDENTIALS_FILE):
        print("Attempting to load credentials from:", CREDENTIALS_FILE)
        api = WithingsApi(load_credentials(), refresh_cb=save_credentials)
        try:
            api.user_get_device()
        except MissingTokenError:
            os.remove(CREDENTIALS_FILE)
            print(
                "Credentials in file are expired. Re-starting auth procedure..."
            )

    if not path.isfile(CREDENTIALS_FILE):
        print("Attempting to get credentials...")
        auth: Final = WithingsAuth(
            client_id=args.client_id,
            consumer_secret=args.consumer_secret,
            callback_uri=args.callback_uri,
            mode=None if args.live_data else "demo",
            scope=(
                AuthScope.USER_ACTIVITY,
                AuthScope.USER_METRICS,
                AuthScope.USER_INFO,
                AuthScope.USER_SLEEP_EVENTS,
            ),
        )

        authorize_url: Final = auth.get_authorize_url()
        print("Goto this URL in your browser and authorize:", authorize_url)
        print("Once you are redirected, copy and paste the whole url"
              "(including code) here.")
        redirected_uri: Final = input("Provide the entire redirect uri: ")
        redirected_uri_params: Final = dict(
            parse.parse_qsl(parse.urlsplit(redirected_uri).query))
        auth_code: Final = redirected_uri_params["code"]

        print("Getting credentials with auth code", auth_code)
        save_credentials(auth.get_credentials(auth_code))

        api = WithingsApi(load_credentials(), refresh_cb=save_credentials)

    # This only tests the refresh token. Token refresh is handled automatically by the api so you should not
    # need to use this method so long as your code regularly (every 3 hours or so) requests data from withings.
    orig_access_token = api.get_credentials().access_token
    print("Refreshing token...")
    api.refresh_token()
    assert orig_access_token != api.get_credentials().access_token

    print("Getting devices...")
    assert api.user_get_device() is not None

    print("Getting measures...")
    assert (api.measure_get_meas(startdate=arrow.utcnow().shift(days=-21),
                                 enddate=arrow.utcnow()) is not None)

    print("Getting activity...")
    assert (api.measure_get_activity(
        startdateymd=arrow.utcnow().shift(days=-21), enddateymd=arrow.utcnow())
            is not None)

    print("Getting sleep...")
    assert (api.sleep_get(
        data_fields=GetSleepField,
        startdate=arrow.utcnow().shift(days=-2),
        enddate=arrow.utcnow(),
    ) is not None)

    print("Getting sleep summary...")
    assert (api.sleep_get_summary(
        data_fields=GetSleepSummaryField,
        startdateymd=arrow.utcnow().shift(days=-2),
        enddateymd=arrow.utcnow(),
    ) is not None)

    print("Getting subscriptions...")
    assert api.notify_list() is not None

    print("Successfully finished.")
Пример #9
0
def main() -> None:
    """Run main function."""
    parser = argparse.ArgumentParser(description="Process some integers.")
    parser.add_argument(
        "--client-id",
        dest="client_id",
        help="Client id provided by withings.",
        required=True,
    )
    parser.add_argument(
        "--consumer-secret",
        dest="consumer_secret",
        help="Consumer secret provided by withings.",
        required=True,
    )
    parser.add_argument(
        "--callback-uri",
        dest="callback_uri",
        help="Callback URI configured for withings application.",
        required=True,
    )

    args = parser.parse_args()

    if path.isfile(CREDENTIALS_FILE):
        print("Using credentials saved in:", CREDENTIALS_FILE)
        with open(CREDENTIALS_FILE, "rb") as file_handle:
            credentials = pickle.load(file_handle)
    else:
        print("Attempting to get credentials...")
        auth = WithingsAuth(
            client_id=args.client_id,
            consumer_secret=args.consumer_secret,
            callback_uri=args.callback_uri,
            mode="demo",
            scope=(
                AuthScope.USER_ACTIVITY,
                AuthScope.USER_METRICS,
                AuthScope.USER_INFO,
                AuthScope.USER_SLEEP_EVENTS,
            ),
        )

        authorize_url = auth.get_authorize_url()
        print("Goto this URL in your browser and authorize:", authorize_url)
        print("Once you are redirected, copy and paste the whole url"
              "(including code) here.")
        redirected_uri = input("Provide the entire redirect uri: ")
        redirected_uri_params = dict(
            parse.parse_qsl(parse.urlsplit(redirected_uri).query))
        auth_code = redirected_uri_params["code"]

        print("Getting credentials with auth code", auth_code)
        credentials = auth.get_credentials(auth_code)
        with open(CREDENTIALS_FILE, "wb") as file_handle:
            pickle.dump(credentials, file_handle)

    refresh_cb = MagicMock()
    api = WithingsApi(credentials, refresh_cb=refresh_cb)

    print("Getting devices...")
    assert api.measure_get_meas() is not None

    print("Refreshing token...")
    refresh_cb.reset_mock()
    api.refresh_token()
    refresh_cb.assert_called_once()

    print("Getting measures...")
    assert (api.measure_get_meas(startdate=arrow.utcnow().shift(days=-21),
                                 enddate=arrow.utcnow()) is not None)

    print("Getting activity...")
    assert (api.measure_get_activity(
        startdateymd=arrow.utcnow().shift(days=-21), enddateymd=arrow.utcnow())
            is not None)

    print("Getting sleep...")
    assert (api.sleep_get(startdate=arrow.utcnow().shift(days=-2),
                          enddate=arrow.utcnow()) is not None)

    print("Getting sleep summary...")
    assert (api.sleep_get_summary(startdateymd=arrow.utcnow().shift(days=-2),
                                  enddateymd=arrow.utcnow()) is not None)

    print("Getting subscriptions...")
    assert api.notify_list() is not None

    print("Successfully finished.")
Пример #10
0
from withings_api import WithingsAuth, WithingsApi, AuthScope
from withings_api.common import get_measure_value, MeasureType, NotifyAppli
from enum import Enum, IntEnum

auth = WithingsAuth(
    client_id='bd7fa1e13e826e59cf239e309f53b765b706e90bdcd4e7f87f9b6378481605af',
    consumer_secret='1739c24a9971681ea82abc4b10a44882584eeaf6334eaebdbfd54df7396270fc',
    callback_uri='https://asia-southeast2-eric-han.cloudfunctions.net/nus-withings-bridge',
    scope=(
        AuthScope.USER_ACTIVITY,
        AuthScope.USER_METRICS,
        AuthScope.USER_INFO,
        AuthScope.USER_SLEEP_EVENTS,
    )
)

authorize_url = auth.get_authorize_url()
# Have the user goto authorize_url and authorize the app. They will be redirected back to your redirect_uri.
print(authorize_url)

code = input("Enter Code: ")
credentials = auth.get_credentials(code)

# Now you are ready to make calls for data.
api = WithingsApi(credentials)

ll = api.notify_list()
print(ll)


Пример #11
0
def main() -> None:
    """Run main function."""
    parser: Final = argparse.ArgumentParser(
        description="Process some integers.")
    parser.add_argument(
        "--client-id",
        dest="client_id",
        help="Client id provided by withings.",
        required=True,
    )
    parser.add_argument(
        "--consumer-secret",
        dest="consumer_secret",
        help="Consumer secret provided by withings.",
        required=True,
    )
    parser.add_argument(
        "--callback-uri",
        dest="callback_uri",
        help="Callback URI configured for withings application.",
        required=True,
    )
    parser.add_argument(
        "--live-data",
        dest="live_data",
        action="store_true",
        help=
        "Should we run against live data? (Removal of .credentials file is required before running)",
    )

    args: Final = parser.parse_args()

    if not path.isfile(CREDENTIALS_FILE):
        print("Attempting to get credentials...")
        auth: Final = WithingsAuth(
            client_id=args.client_id,
            consumer_secret=args.consumer_secret,
            callback_uri=args.callback_uri,
            mode=None if args.live_data else "demo",
            scope=(
                AuthScope.USER_ACTIVITY,
                AuthScope.USER_METRICS,
                AuthScope.USER_INFO,
                AuthScope.USER_SLEEP_EVENTS,
            ),
        )

        authorize_url: Final = auth.get_authorize_url()
        print("Goto this URL in your browser and authorize:", authorize_url)
        print("Once you are redirected, copy and paste the whole url"
              "(including code) here.")
        redirected_uri: Final = input("Provide the entire redirect uri: ")
        redirected_uri_params: Final = dict(
            parse.parse_qsl(parse.urlsplit(redirected_uri).query))
        auth_code: Final = redirected_uri_params["code"]

        print("Getting credentials with auth code", auth_code)
        save_credentials(auth.get_credentials(auth_code))

    api: Final = WithingsApi(load_credentials(), refresh_cb=save_credentials)

    print("Getting devices...")
    assert api.user_get_device() is not None

    print("Getting measures...")
    assert (api.measure_get_meas(startdate=arrow.utcnow().shift(days=-21),
                                 enddate=arrow.utcnow()) is not None)

    print("Getting activity...")
    assert (api.measure_get_activity(
        startdateymd=arrow.utcnow().shift(days=-21), enddateymd=arrow.utcnow())
            is not None)

    print("Getting sleep...")
    assert (api.sleep_get(startdate=arrow.utcnow().shift(days=-2),
                          enddate=arrow.utcnow()) is not None)

    print("Getting sleep summary...")
    assert (api.sleep_get_summary(startdateymd=arrow.utcnow().shift(days=-2),
                                  enddateymd=arrow.utcnow()) is not None)

    print("Getting subscriptions...")
    assert api.notify_list() is not None

    print("Successfully finished.")
Пример #12
0
class CommWithings:

    class NotAuthorized(Exception):
        pass

    def __init__(self):
        self.api = None
        self.scale = Settings.objects.first().default_scale

        self.auth = WithingsAuth(
            client_id=settings.WITHINGS_API_CLIENT_ID,
            consumer_secret=settings.WITHINGS_API_CONSUMER_SECRET,
            callback_uri=settings.WITHINGS_API_CALLBACK_URI,
            scope=(
                AuthScope.USER_ACTIVITY,
                AuthScope.USER_METRICS,
                AuthScope.USER_INFO,
                AuthScope.USER_SLEEP_EVENTS,
            ),
        )

    def connect(self) -> bool:
        withings_settings = Settings.objects.first()
        if withings_settings.token:
            logger.info(f'Attempting to load credentials from database:')
            self.api = WithingsApi(self._load_credentials(),
                                   refresh_cb=self._save_credentials)
            try:
                self.api.user_get_device()

                orig_access_token = self.api.get_credentials().access_token
                logger.info('Refreshing token...')
                self.api.refresh_token()
                assert orig_access_token \
                       != self.api.get_credentials().access_token
            except (MissingTokenError, AuthFailedException):
                withings_settings.token = None
                withings_settings.save()
                self.api = None
                logger.info('Credentials in file are expired.')
                raise CommWithings.NotAuthorized
        else:
            logger.info('No credentials file found.')
            raise CommWithings.NotAuthorized

        return self.api is not None

    def authorize_request(self):
        logger.info('Attempting to get credentials...')

        authorize_url = self.get_authorize_url()
        subject = 'Withings API authorization request'
        html_message = (
            f'<html><body><div>'
            f'The application needs to be authorized with Withings API.</div>'
            f'<div>Go to this <a href="{authorize_url}">link</a>'
            f' and authorize.</div>'
            f'</body></html>'
        )
        plain_message = strip_tags(html_message)
        mail_admins(subject, plain_message, html_message=html_message)

    def get_authorize_url(self):
        return self.auth.get_authorize_url()

    def save_credentials(self, auth_code):
        self._save_credentials(self.auth.get_credentials(auth_code))

    @classmethod
    def _save_credentials(cls, credentials: CredentialsType) -> None:
        """Save credentials to a file."""
        logger.info(f'Saving credentials in database')
        cls._log_credentials(credentials)
        withings_settings = Settings.objects.first()
        withings_settings.token = pickle.dumps(credentials)
        withings_settings.save()

    @classmethod
    def _load_credentials(cls) -> CredentialsType:
        """Load credentials from a file."""
        logger.info(f'Using credentials from database')

        credentials = cast(CredentialsType,
                           pickle.loads(Settings.objects.first().token))
        cls._log_credentials(credentials)

    @staticmethod
    def _log_credentials(credentials: CredentialsType):
        logger.info(
            f'Credential properties: '
            f'  Token:         {credentials.access_token}'
            f'  Refresh Token: {credentials.refresh_token}'
            f'  Client ID: {credentials.client_id}'
            f'  Expiry: {credentials.token_expiry}'
        )


    def import_data(self, date_from, date_to):
        assert self.api is not None
        assert self.api.user_get_device() is not None

        meas_result = self.api.measure_get_meas(
            startdate=date_from,
            enddate=date_to,
            # lastupdate=1601478000,
            lastupdate=None,
            category=MeasureGetMeasGroupCategory.REAL)

        api_to_django = {
            MeasureType.WEIGHT: 'weight',
            MeasureType.FAT_RATIO: 'fat_pct',
        }

        dict_meas = [
            {
                **{
                    api_to_django[measure.type]: float(
                        measure.value * pow(10, measure.unit))
                    for measure in grp.measures
                },
                'measure_date': grp.date.datetime
            }
            for grp in query_measure_groups(
                    meas_result,
                    with_measure_type=cast(Tuple, api_to_django.keys())
            )
        ]
        logger.debug(f'Values from Withings API: {dict_meas}')

        db_values = list(Measurement.objects.filter(
            measure_date__range=[date_from.datetime, date_to.datetime]
        ).values('measure_date', *api_to_django.values()))
        logger.debug(f'Values from Django DB: {db_values}')

        results = {'add': 0, 'del': 0}
        for i in dict_meas + db_values:
            if i not in db_values:
                logger.info(f'Add to DB: {i}')
                Measurement.objects.create(
                    scale=self.scale,
                    **i
                )
                results['add'] += 1
            if i not in dict_meas:
                logger.info(f'Delete from DB: {i}')
                Measurement.objects.get(**i).delete()
                results['del'] += 1

        logger.info(f'Import results: {results["add"]} addition,'
                    f' {results["del"]} deletion')
Пример #13
0
from urllib import parse
import requests

from flask import Flask, request, render_template, jsonify
import json
app = Flask(__name__)

clientid = "7f5486f78731e761c99878e8e37d540f5868a99c12a16089be227b372a366c36"
consumer_secrete = "efa34f8ae8542f4de35ce0a4b7108421e3d32a6bd9ae8eecc0d8efcb6ff29d7a"
calbackuri = "https://vocobot.herokuapp.com/"

auth = WithingsAuth(client_id=clientid,
                    consumer_secret=consumer_secrete,
                    callback_uri=calbackuri,
                    scope=(
                        AuthScope.USER_ACTIVITY,
                        AuthScope.USER_METRICS,
                        AuthScope.USER_INFO,
                        AuthScope.USER_SLEEP_EVENTS,
                    ))


@app.route("/", methods=["GET", "POST"])
def index():
    authorize_url = auth.get_authorize_url()
    return render_template("index.html", url=authorize_url)


@app.route("/authorize", methods=["POST", "GET"])
def authorize():
    if request.method == "POST":