@@ -54,3 +54,6 @@ docs/_build/
|
|||||||
target/
|
target/
|
||||||
google.json
|
google.json
|
||||||
fitbit.yaml
|
fitbit.yaml
|
||||||
|
|
||||||
|
# vim swap files
|
||||||
|
.*.swp
|
||||||
|
|||||||
@@ -20,17 +20,22 @@ Use `pip` to install the required packages,
|
|||||||
|
|
||||||
### Fitbit Credentials
|
### Fitbit Credentials
|
||||||
|
|
||||||
[Register a Fitbit application](https://dev.fitbit.com/apps/new). Note the client key and secret.
|
[Register a Fitbit application](https://dev.fitbit.com/apps/new) with:
|
||||||
|
* OAuth 2.0 Application Type: `Personal`
|
||||||
|
* Callback URL: `http://localhost:8080/`
|
||||||
|
* Default Access Type: `Read-Only`
|
||||||
|
* any values you want for application name, website, organization, and organization website
|
||||||
|
Note the resulting `OAuth 2.0 Client ID` and `Client Secret`.
|
||||||
|
|
||||||
Run `auth_fitbit.py` to get credentials for read access to a user's data,
|
Run `auth_fitbit.py` to get credentials for read access to a user's data,
|
||||||
|
|
||||||
$ python auth_fitbit.py [FITBIT CLIENT KEY] [FITBIT CLIENT SECRET]
|
$ python auth_fitbit.py [FITBIT CLIENT ID] [FITBIT CLIENT SECRET]
|
||||||
|
|
||||||
This scripts open a browser window where you can log in to your Fitbit account and authorize the app to "access your profile and data". When you accept, the site will give you a string to copy and paste back into the script, which then writes the credentials to a local file named `fitbit.yaml`.
|
This scripts open a browser window where you can log in to your Fitbit account and authorize the app to "access your profile and data". When you accept, the script writes the credentials to a local file named `fitbit.yaml`.
|
||||||
|
|
||||||
### Google Credentials
|
### Google Credentials
|
||||||
|
|
||||||
[Create a project in Google Developers Console and enable the fitness API](https://console.developers.google.com/flows/enableapi?apiid=fitness). Create OAuth client ID with Other/Desktop type. Note the client id and client secret.
|
[Create a project in Google Developers Console and enable the fitness API](https://console.developers.google.com/flows/enableapi?apiid=fitness). Create an OAuth client ID with `Other UI` type and select `User data`. Note the client id and client secret.
|
||||||
|
|
||||||
Run `auth_google.py` to get credentials for write access to a user's body data,
|
Run `auth_google.py` to get credentials for write access to a user's body data,
|
||||||
|
|
||||||
|
|||||||
+86
-55
@@ -1,78 +1,109 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
"""
|
"""
|
||||||
This was taken, and modified from python-fitbit/gather_keys_cli.py,
|
This was taken, and modified from python-fitbit/gather_keys_oauth2.py,
|
||||||
License reproduced below.
|
License reproduced below.
|
||||||
|
|
||||||
--------------------------
|
--------------------------
|
||||||
The MIT License
|
Copyright 2012-2015 ORCAS
|
||||||
|
|
||||||
Copyright (c) 2007 Leah Culver
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
Unless required by applicable law or agreed to in writing, software
|
||||||
all copies or substantial portions of the Software.
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
See the License for the specific language governing permissions and
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
limitations under the License.
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
|
|
||||||
Example consumer. This is not recommended for production.
|
|
||||||
Instead, you'll want to create your own subclass of OAuthClient
|
|
||||||
or find one that works with your web framework.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import threading
|
||||||
|
import traceback
|
||||||
import webbrowser
|
import webbrowser
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from fitbit.api import FitbitOauthClient
|
from base64 import b64encode
|
||||||
|
import cherrypy
|
||||||
|
from fitbit.api import FitbitOauth2Client
|
||||||
|
from oauthlib.oauth2.rfc6749.errors import MismatchingStateError, MissingTokenError
|
||||||
|
from requests_oauthlib import OAuth2Session
|
||||||
|
|
||||||
|
|
||||||
def gather_keys():
|
class OAuth2Server:
|
||||||
# setup
|
def __init__(self, client_id, client_secret,
|
||||||
client = FitbitOauthClient(CLIENT_KEY, CLIENT_SECRET)
|
redirect_uri='http://localhost:8080/'):
|
||||||
|
""" Initialize the FitbitOauth2Client """
|
||||||
|
self.redirect_uri = redirect_uri
|
||||||
|
self.success_html = """
|
||||||
|
<h1>You are now authorized to access the Fitbit API!</h1>
|
||||||
|
<br/><h3>You can close this window</h3>"""
|
||||||
|
self.failure_html = """
|
||||||
|
<h1>ERROR: %s</h1><br/><h3>You can close this window</h3>%s"""
|
||||||
|
self.oauth = FitbitOauth2Client(client_id, client_secret)
|
||||||
|
|
||||||
# get request token
|
def browser_authorize(self):
|
||||||
token = client.fetch_request_token()
|
"""
|
||||||
|
Open a browser to the authorization url and spool up a CherryPy
|
||||||
|
server to accept the response
|
||||||
|
"""
|
||||||
|
url, _ = self.oauth.authorize_token_url(redirect_uri=self.redirect_uri)
|
||||||
|
# Open the web browser in a new thread for command-line browser support
|
||||||
|
threading.Timer(1, webbrowser.open, args=(url,)).start()
|
||||||
|
cherrypy.quickstart(self)
|
||||||
|
|
||||||
stderr = os.dup(2)
|
@cherrypy.expose
|
||||||
os.close(2)
|
def index(self, state, code=None, error=None):
|
||||||
os.open(os.devnull, os.O_RDWR)
|
"""
|
||||||
webbrowser.open(client.authorize_token_url())
|
Receive a Fitbit response containing a verification code. Use the code
|
||||||
os.dup2(stderr, 2)
|
to fetch the access_token.
|
||||||
try:
|
"""
|
||||||
verifier = raw_input('Verifier: ')
|
error = None
|
||||||
except NameError:
|
if code:
|
||||||
# Python 3.x
|
try:
|
||||||
verifier = input('Verifier: ')
|
self.oauth.fetch_access_token(code, self.redirect_uri)
|
||||||
|
except MissingTokenError:
|
||||||
|
error = self._fmt_failure(
|
||||||
|
'Missing access token parameter.</br>Please check that '
|
||||||
|
'you are using the correct client_secret')
|
||||||
|
except MismatchingStateError:
|
||||||
|
error = self._fmt_failure('CSRF Warning! Mismatching state')
|
||||||
|
else:
|
||||||
|
error = self._fmt_failure('Unknown error while authenticating')
|
||||||
|
# Use a thread to shutdown cherrypy so we can return HTML first
|
||||||
|
self._shutdown_cherrypy()
|
||||||
|
return error if error else self.success_html
|
||||||
|
|
||||||
# get access token
|
def _fmt_failure(self, message):
|
||||||
token = client.fetch_access_token(verifier)
|
tb = traceback.format_tb(sys.exc_info()[2])
|
||||||
return token
|
tb_html = '<pre>%s</pre>' % ('\n'.join(tb)) if tb else ''
|
||||||
|
return self.failure_html % (message, tb_html)
|
||||||
|
|
||||||
|
def _shutdown_cherrypy(self):
|
||||||
|
""" Shutdown cherrypy in one second, if it's running """
|
||||||
|
if cherrypy.engine.state == cherrypy.engine.states.STARTED:
|
||||||
|
threading.Timer(1, cherrypy.engine.exit).start()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if not (len(sys.argv) == 3):
|
||||||
|
print("Arguments 'client ID', 'client secret' are required")
|
||||||
|
sys.exit(1)
|
||||||
|
client_id = sys.argv[1]
|
||||||
|
client_secret = sys.argv[2]
|
||||||
|
|
||||||
|
server = OAuth2Server(client_id, client_secret)
|
||||||
|
server.browser_authorize()
|
||||||
|
|
||||||
|
credentials = dict(
|
||||||
|
client_id=client_id,
|
||||||
|
client_secret=client_secret,
|
||||||
|
access_token=server.oauth.token['access_token'],
|
||||||
|
refresh_token=server.oauth.token['refresh_token'])
|
||||||
|
yaml.dump(credentials, open('fitbit.yaml', 'w'))
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
if not (len(sys.argv) == 3):
|
main()
|
||||||
print("Arguments 'client key', 'client secret' are required")
|
|
||||||
sys.exit(1)
|
|
||||||
CLIENT_KEY = sys.argv[1]
|
|
||||||
CLIENT_SECRET = sys.argv[2]
|
|
||||||
|
|
||||||
keys = gather_keys()
|
|
||||||
credentials = dict(
|
|
||||||
client_key=CLIENT_KEY,
|
|
||||||
client_secret=CLIENT_SECRET,
|
|
||||||
resource_owner_key=keys['oauth_token'].encode('ascii'),
|
|
||||||
resource_owner_secret=keys['oauth_token_secret'].encode('ascii'))
|
|
||||||
yaml.dump(credentials, open('fitbit.yaml', 'w'))
|
|
||||||
|
|||||||
+8
-16
@@ -1,16 +1,8 @@
|
|||||||
PyYAML==3.11
|
oauthlib == 1.0.3
|
||||||
fitbit==0.1.2
|
google_api_python_client == 1.5.0
|
||||||
google-api-python-client==1.3.1
|
cherrypy == 5.4.0
|
||||||
httplib2==0.9
|
python_dateutil == 2.5.3
|
||||||
oauth2client==1.4.3
|
fitbit == 0.2.2
|
||||||
oauthlib==0.7.2
|
httplib2 == 0.9.2
|
||||||
pyasn1==0.1.7
|
requests_oauthlib == 0.6.1
|
||||||
pyasn1-modules==0.0.5
|
PyYAML == 3.11
|
||||||
python-dateutil==2.3
|
|
||||||
requests==2.5.0
|
|
||||||
requests-oauthlib==0.4.2
|
|
||||||
rsa==3.1.4
|
|
||||||
simplejson==3.6.5
|
|
||||||
six==1.8.0
|
|
||||||
uritemplate==0.6
|
|
||||||
wsgiref==0.1.2
|
|
||||||
|
|||||||
Reference in New Issue
Block a user