From 6687c063a03aa4fb5a75877bbb95baaa7c897e8e Mon Sep 17 00:00:00 2001 From: "M.Weirauch" Date: Fri, 2 Jun 2023 16:00:17 +0200 Subject: [PATCH] First commit --- .env | 7 ++ package.json | 23 ++++++ src/main.js | 202 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 232 insertions(+) create mode 100644 .env create mode 100644 package.json create mode 100644 src/main.js diff --git a/.env b/.env new file mode 100644 index 0000000..a14b6a1 --- /dev/null +++ b/.env @@ -0,0 +1,7 @@ +#Personl TestAPI +#FITBIT_CLIENT_ID=23QX5D +#FITBIT_CLIENT_SECRET=801d6a43fb2fe015b10362376928b617 + +#Server TestAPI2 +FITBIT_CLIENT_ID=23QX94 +FITBIT_CLIENT_SECRET=1418c9846a17b734098ac6c49aab235f \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..ade4297 --- /dev/null +++ b/package.json @@ -0,0 +1,23 @@ +{ + "name": "fitbit", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "start": "node ./src/main.js", + "start:dev": "npx nodemon -w ./src ./src/main.js", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "dotenv": "^16.0.3", + "express": "^4.18.2", + "moment": "^2.29.4", + "node-fetch": "^2.6.11" + }, + "devDependencies": { + "nodemon": "^2.0.22" + } +} diff --git a/src/main.js b/src/main.js new file mode 100644 index 0000000..51b19f2 --- /dev/null +++ b/src/main.js @@ -0,0 +1,202 @@ +const crypto = require('crypto') +const express = require('express') +const fetch = require('node-fetch') +var moment = require('moment'); + +require('dotenv').config(); + +if (require.main === module) { + main() +} + +async function main () { + try { + const router = express() + const verifier = base64UrlEncode(crypto.randomBytes(64)) // <1> + const challenge = base64UrlEncode(sha256Hash(Buffer.from(verifier))) // <2> + console.log('env ', process.env.FITBIT_CLIENT_ID, process.env.FITBIT_CLIENT_SECRET) + + router.get('/signin', (req, res) => { // <3> + const search = '?' + new URLSearchParams({ + 'client_id': process.env.FITBIT_CLIENT_ID, + 'response_type': 'code', + 'code_challenge': challenge, + 'code_challenge_method': 'S256', + // 'scope': 'heartrate', + 'scope': 'activity', + + }) + + const url = 'https://www.fitbit.com/oauth2/authorize' + search + res.redirect(url) + }) + + router.get('/callback', async (req, res, next) => { // <4> + try { + const user = process.env.FITBIT_CLIENT_ID + const pass = process.env.FITBIT_CLIENT_SECRET + const credentials = Buffer.from(`${user}:${pass}`).toString('base64') + const tokenUrl = 'https://api.fitbit.com/oauth2/token' + const tokenResponse = await fetch(tokenUrl, { // <5> + method: 'POST', + headers: { + 'Authorization': `Basic ${credentials}`, + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: new URLSearchParams({ + 'client_id': process.env.FITBIT_CLIENT_ID, + 'code': req.query.code, + 'code_verifier': verifier, + 'grant_type': 'authorization_code', + }).toString(), + }) + + const tokenBody = await tokenResponse.json() + console.log('tokenBody', tokenBody) + + if (tokenBody.errors) { // <6> + console.error(tokenBody.errors[0].message) + res.status(500).end() + return + } + + const userId = '-' + const date = 'today' + const detailLevel = '1sec' + // const dataUrl = 'https://api.fitbit.com/' + [ + // '1', + // 'user', + // userId, + // 'activities', + // 'heart', + // 'date', + // date, + // '1d', + // `${detailLevel}.json` + // ].join('/') + const today = moment(); + const dataUrl = 'https://api.fitbit.com/' + [ + '1', + 'user', + userId, + 'activities', + 'date', + `${today.format('YYYY-MM-D')}.json` + ].join('/') + console.log('URL ', dataUrl) + + const dataResponse = await fetch(dataUrl, { // <7> + method: 'GET', + headers: { + 'Authorization': `Bearer ${tokenBody['access_token']}`, + }, + }) + + const dataBody = await dataResponse.json() + + if (dataBody.errors) { // <8> + console.error(dataBody.errors[0].message) + res.status(500).end() + return + } + + res.type('text/plain') // <9> + .send(JSON.stringify(dataBody, null, 2)) + } catch (err) { + next(err) + } + }) + + router.get('/show', async(req, res) => { // <3> + const today = moment(); + var result = '' + var userId = '55QCL4'; + var userToken = 'eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIyM1FYOTQiLCJzdWIiOiI1NVFDTDQiLCJpc3MiOiJGaXRiaXQiLCJ0eXAiOiJhY2Nlc3NfdG9rZW4iLCJzY29wZXMiOiJyYWN0IiwiZXhwIjoxNjg1NzI1OTcyLCJpYXQiOjE2ODU2OTcxNzJ9.k94QyIMqoBOfyqAzvkjeFkn7SFmKOae5l4Y4AqRSzCg'; + var dataUrl = 'https://api.fitbit.com/' + [ + '1', + 'user', + userId, + 'activities', + 'date', + `${today.format('YYYY-MM-D')}.json` + ].join('/') + console.log('URL ', dataUrl) + + var dataResponse = await fetch(dataUrl, { // <7> + method: 'GET', + headers: { + 'Authorization': `Bearer ${userToken}`, + }, + }) + + var dataBody = await dataResponse.json() + + if (dataBody.errors) { // <8> + console.error(dataBody.errors[0].message) + res.status(500).end() + return + } + var string = JSON.stringify(dataBody, null, 2); + var data = JSON.parse(string); + var steps = data.summary['steps']; + console.log(steps); + result = today.toDate()+ ' \nSchritte Marcus '+ steps ; + // res.type('text/plain') // <9> + // .send('Steps Marcus '+ steps ) //dataBody.summary.steps + + userId = '7NBCBG'; + userToken = 'eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIyM1FYOTQiLCJzdWIiOiI3TkJDQkciLCJpc3MiOiJGaXRiaXQiLCJ0eXAiOiJhY2Nlc3NfdG9rZW4iLCJzY29wZXMiOiJyYWN0IiwiZXhwIjoxNjg1NzM2MjM2LCJpYXQiOjE2ODU3MDc0MzZ9.5uAKWIeaLHDrQWTQ7099N-QkrpHUqAIfvtXEIZcoaUY'; + dataUrl = 'https://api.fitbit.com/' + [ + '1', + 'user', + userId, + 'activities', + 'date', + `${today.format('YYYY-MM-D')}.json` + ].join('/') + console.log('URL ', dataUrl) + + dataResponse = await fetch(dataUrl, { // <7> + method: 'GET', + headers: { + 'Authorization': `Bearer ${userToken}`, + }, + }) + + dataBody = await dataResponse.json() + + if (dataBody.errors) { // <8> + console.error(dataBody.errors[0].message) + res.status(500).end() + return + } + string = JSON.stringify(dataBody, null, 2); + data = JSON.parse(string); + steps = data.summary['steps']; + console.log(steps) + result = result + '\n' + 'Schritte Ute '+ steps + res.type('text/plain') // <9> + // .send('Steps Ute'+ steps ) //dataBody.summary.steps + .send(result) + }) + + + router.listen(3000) + } catch (err) { + console.error(err) + } +} + +function base64UrlEncode (buffer) { // <10> + return buffer.toString('base64') + .replace(/\+/g, '-') + .replace(/\//g, '_') + .replace(/=/g, '') +} + +function sha256Hash (buffer) { // <11> + const hash = crypto.createHash('sha256') + + hash.update(buffer) + return hash.digest() +} \ No newline at end of file