Browse code

strava upload with oauth (unsecured for now) and clay settings are working

louis.jonget authored on21/10/2022 16:01:55
Showing4 changed files
... ...
@@ -1,9 +1,12 @@
1
-/*STRAVA_API
1
+/*STRAVA_API Workflow
2
+
3
+TODO CHANGE CLIENT_ID and password when publish the app
2 4
 
3 5
 OAuth2.0 strava / pebble
4 6
 
5 7
 1 - get activity:write authorization (once and for all)
6
-    GET https://www.strava.com/oauth/authorize?client_id=94880&response_type=code&redirect_uri=http://strava.jonget.fr&approval_prompt=force&state=bike_companion&scope=activity:write
8
+    GET https://www.strava.com/oauth/authorize?client_id=14883&response_type=code&redirect_uri=http://www.pebblebike.com/strava-se/authorize.php&scope=write
9
+    GET https://www.strava.com/oauth/authorize?client_id=94880&response_type=code&redirect_uri=http://strava.jonget.fr&scope=activity:write
7 10
     monitor state, code and scope (as upload can be unchecked)!
8 11
     code is short lived and one time usage
9 12
 2 - get tokens in exchange of code (make it done by jonget.fr because of secret ? )
10 13
Binary files a/build/bike_companion.pbw and b/build/bike_companion.pbw differ
... ...
@@ -1,90 +1,99 @@
1
-module.exports = [{
2
-        type: "section",
3
-        items: [{
4
-                type: "heading",
5
-                defaultValue: "Locate Me"
1
+module.exports = [
2
+    {
3
+        "type": "section",
4
+        "items": [
5
+            {
6
+                "type": "heading",
7
+                "defaultValue": "Locate Me"
6 8
             },
7 9
             {
8
-                type: "toggle",
9
-                messageKey: "ping_location_enable",
10
-                label: "Locate me on another server"
10
+                "type": "toggle",
11
+                "messageKey": "ping_location_enabled",
12
+                "label": "Locate me on another server"
11 13
             },
12 14
             {
13
-                type: "text",
14
-                messageKey: "ping_location_url",
15
-                label: "full URL of server getting the location"
15
+                "type": "input",
16
+                "messageKey": "ping_location_url",
17
+                "label": "full URL (https://domain/path/endpoint.php) of server getting the location"
16 18
             },
17 19
             {
18
-                type: "input",
19
-                messageKey: "ping_location_login",
20
-                label: "Login (unused)"
20
+                "type": "input",
21
+                "messageKey": "ping_location_login",
22
+                "label": "Login (unused)"
21 23
             },
22 24
             {
23
-                type: "input",
24
-                messageKey: "ping_location_password",
25
-                label: "Password (unused)",
26
-                attributes: { type: "password" }
25
+                "type": "input",
26
+                "messageKey": "ping_location_password",
27
+                "label": "Password (unused)",
28
+                "attributes": {
29
+                    "type": "password"
30
+                }
27 31
             }
28 32
         ]
29
-    }, {
30
-        type: "section",
31
-        items: [{
32
-                type: "heading",
33
-                defaultValue: "Send GPX to another server"
34
-            },
33
+    },
34
+    {
35
+        "type": "section",
36
+        "items": [
35 37
             {
36
-                type: "toggle",
37
-                messageKey: "gpx_web_enable",
38
-                label: "Send GPX to another server"
38
+                "type": "heading",
39
+                "defaultValue": "strava"
39 40
             },
40 41
             {
41
-                type: "text",
42
-                messageKey: "gpx_web_url",
43
-                label: "full URL of server getting the GPX"
42
+                "type": "toggle",
43
+                "messageKey": "strava_enabled",
44
+                "label": "strava_enabled"
44 45
             },
45 46
             {
46
-                type: "input",
47
-                messageKey: "gpx_web_login",
48
-                label: "Login (unused)"
47
+                "type": "text",
48
+                "defaultValue": "Grant this application access to upload to Strava<br/><a onclick='return confirm(&quot;Have you saved your changes? They would be lost if you continue.&quot;)' href='https://www.strava.com/oauth/authorize?client_id=94880&response_type=code&redirect_uri=http://strava.jonget.fr&approval_prompt=force&state=bike_companion&scope=activity:write'><img src='data:image/png;base64,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'/></a>"
49 49
             },
50 50
             {
51
-                type: "input",
52
-                messageKey: "gpx_web_password",
53
-                label: "Password (unused)",
54
-                attributes: { type: "password" }
51
+                "type": "toggle",
52
+                "messageKey": "strava_automatic_upload",
53
+                "label": "Automatic upload at the end of the track"
55 54
             }
56 55
         ]
57 56
     },
58 57
     {
59
-        type: "section",
60
-        items: [{
61
-                type: "heading",
62
-                defaultValue: "strava"
58
+        "type": "section",
59
+        "items": [
60
+            {
61
+                "type": "heading",
62
+                "defaultValue": "Send GPX to another server"
63
+            },
64
+            {
65
+                "type": "toggle",
66
+                "messageKey": "gpx_web_enabled",
67
+                "label": "Send GPX to another server"
63 68
             },
64 69
             {
65
-                type: "text",
66
-                defaultValue: "Grant this application access to upload to Strava<br/><a onclick='return confirm(&quot;Have you saved your changes? They would be lost if you continue.&quot;)' href='https://www.strava.com/oauth/authorize?client_id=94880&response_type=code&redirect_uri=http://strava.jonget.fr&approval_prompt=force&state=bike_companion&scope=activity:write'><img src='data:image/png;base64,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'/></a>"
70
+                "type": "input",
71
+                "messageKey": "gpx_web_url",
72
+                "label": "full URL (https://domain/path/endpoint.php) of server getting the GPX"
67 73
             },
68 74
             {
69
-                type: "toggle",
70
-                messageKey: "strava_upload",
71
-                label: "strava_upload"
75
+                "type": "input",
76
+                "messageKey": "gpx_web_login",
77
+                "label": "Login (unused)"
72 78
             },
73 79
             {
74
-                type: "toggle",
75
-                messageKey: "strava_automatic_upload",
76
-                label: "Automatic upload at the end of the track"
80
+                "type": "input",
81
+                "messageKey": "gpx_web_password",
82
+                "label": "Password (unused)",
83
+                "attributes": {
84
+                    "type": "password"
85
+                }
77 86
             }
78 87
         ]
79 88
     },
80 89
     {
81
-        type: "toggle",
82
-        messageKey: "debug",
83
-        label: "Debug"
90
+        "type": "toggle",
91
+        "messageKey": "debug",
92
+        "label": "Debug"
84 93
     },
85 94
     {
86
-        type: "submit",
87
-        id: "submitButton",
88
-        defaultValue: "Save"
95
+        "type": "submit",
96
+        "id": "submitButton",
97
+        "defaultValue": "Save"
89 98
     }
90 99
 ];
91 100
\ No newline at end of file
... ...
@@ -3,63 +3,6 @@ var clayConfig = require('./config');
3 3
 var clay = new Clay(clayConfig, null, { autoHandleEvents: false });
4 4
 var messageKeys = require('message_keys');
5 5
 
6
-Pebble.addEventListener('showConfiguration', function(e) {
7
-
8
-    // This is an example of how you might load a different config based on platform.
9
-    var platform = clay.meta.activeWatchInfo.platform || 'aplite';
10
-    if (platform === 'aplite') {
11
-        clay.config = clayConfigAplite;
12
-    }
13
-
14
-    Pebble.openURL(clay.generateUrl());
15
-});
16
-
17
-Pebble.addEventListener('webviewclosed', function(t) {
18
-    if (!t || t.response) {
19
-        try {
20
-            if (data = JSON.parse(t.response), data.strava) {
21
-                //data.strava will be like this :
22
-                // {"code":"db896b06f89804997a8088320fba755e6299c0d6","scope":"read,activity:write","state":"bike_companion"}
23
-                // so need to parse it correctly
24
-                //console.log("strava temp code to exchange to access token : " + data.code)
25
-                // placeholder to get token from code from php
26
-                return token
27
-            }
28
-        } catch (t) {
29
-            i && console.error("Parsing error:", t)
30
-        }
31
-        var dict = clay.getSettings(t.response);
32
-
33
-        /* assess if needed to send setting to watch as already in phone (done with "getsettings")
34
-        m.live_mmt_enable = dict[p.live_mmt_enable]
35
-        m.live_mmt_login = dict[p.live_mmt_login]
36
-        m.live_mmt_password = dict[p.live_mmt_password]
37
-        m.live_jayps_enable = dict[p.live_jayps_enable]
38
-        m.live_jayps_login = dict[p.live_jayps_login]
39
-        m.live_jayps_password = dict[p.live_jayps_password]
40
-        m.strava_automatic_upload = dict[p.strava_automatic_upload]
41
-    
42
-        i = dict[p.debug]
43
-        console.log("debug:" + i)
44
-        g.setDebug(i)
45
-        h.setDebug(i)
46
-        b.setDebug(i)
47
-        y.setDebug(i)
48
-        m.setDebug(i)
49
-    
50
-        m.save()
51
-        // Assess if needed to send settings values to watch side
52
-        /*
53
-        Pebble.sendAppMessage(dict, function(e) {
54
-            console.log('Sent config data to Pebble');
55
-        }, function(e) {
56
-            console.log('Failed to send config data!');
57
-            console.log(JSON.stringify(e));
58
-        });*/
59
-    }
60
-});
61
-
62
-
63 6
 var message;
64 7
 var gpx_to_strava
65 8
 var gpx_to_web
... ...
@@ -68,410 +11,564 @@ var locate_me
68 11
 var locationInterval;
69 12
 var instantLocationInterval;
70 13
 
14
+// TODO to remove for security
15
+var client_id = "94880";
16
+var client_secret = "08dc170f0fe38f39dd327bea82a28db4400e6f00";
17
+
71 18
 var firstlocationOptions = {
72
-    'enableHighAccuracy': true, // default = false (quick and dirty mode), can be true (more accurate but need more power and time)
73
-    'timeout': 60000, //60s timeout to get a first good signal
74
-    'maximumAge': 0 // no cache
19
+  'enableHighAccuracy': true, // default = false (quick and dirty mode), can be true (more accurate but need more power and time)
20
+  'timeout': 60000, //60s timeout to get a first good signal
21
+  'maximumAge': 0 // no cache
75 22
 };
76 23
 var locationOptions = {
77
-    'enableHighAccuracy': true, // default = false (quick and dirty mode), can be true (more accurate but need more power and time)
78
-    'timeout': 5000, //5s timeout to get a good signal
79
-    'maximumAge': 0 // no cache
24
+  'enableHighAccuracy': true, // default = false (quick and dirty mode), can be true (more accurate but need more power and time)
25
+  'timeout': 5000, //5s timeout to get a good signal
26
+  'maximumAge': 0 // no cache
80 27
 };
81
-var geoloc_id;
28
+
29
+Pebble.addEventListener('showConfiguration', function (e) {
30
+  clay.config = clayConfig;
31
+  console.log("Clay config is showing...")
32
+  Pebble.openURL(clay.generateUrl());
33
+});
34
+
35
+Pebble.addEventListener('webviewclosed', function (t) {
36
+  if (!t || t.response) {
37
+    console.log("Clay config is submitted : " + t.response)
38
+    try {
39
+      if (data = JSON.parse(t.response), data.code && data.scope == "read,activity:write") {
40
+        // data looks like this :
41
+        // {"code":"db896b06f89804997a8088320fba755e6299c0d6","scope":"read,activity:write","state":"bike_companion"}
42
+        // so need to parse it correctly
43
+        //var grantcode = JSON.parse(data.strava.value)
44
+        if (data.state == "bike_companion" && data.scope == "read,activity:write") {
45
+          getTokens(data.code);
46
+        } else {
47
+          console.log("Error on response returned : scope is " + grantcode.scope + " and state is " + grantcode.state);
48
+        }
49
+      } else {
50
+        clay.getSettings(t.response);
51
+        console.log("Clay settings in Localstorage looks like " + localStorage.getItem("clay-settings"));
52
+      }
53
+    } catch (t) {
54
+      console.log("Oauth parsing error, continue on saving clay settings");
55
+      clay.getSettings(t.response);
56
+      console.log("Clay settings in Localstorage looks like " + localStorage.getItem("clay-settings"));
57
+      //set strava to false
58
+    }
59
+
60
+    // dict is not used as intended to send settings to watch
61
+
62
+    /* assess if needed to send setting to watch as already in phone (done with "getsettings")
63
+    m.live_mmt_enable = dict[p.live_mmt_enable]
64
+    m.live_mmt_login = dict[p.live_mmt_login]
65
+    m.live_mmt_password = dict[p.live_mmt_password]
66
+    m.live_jayps_enable = dict[p.live_jayps_enable]
67
+    m.live_jayps_login = dict[p.live_jayps_login]
68
+    m.live_jayps_password = dict[p.live_jayps_password]
69
+    m.strava_automatic_upload = dict[p.strava_automatic_upload]
70
+
71
+    i = dict[p.debug]
72
+    console.log("debug:" + i)
73
+    g.setDebug(i)
74
+    h.setDebug(i)
75
+    b.setDebug(i)
76
+    y.setDebug(i)
77
+    m.setDebug(i)
78
+
79
+    m.save()
80
+    // Assess if needed to send settings values to watch side
81
+    /*
82
+    Pebble.sendAppMessage(dict, function(e) {
83
+        console.log('Sent config data to Pebble');
84
+    }, function(e) {
85
+        console.log('Failed to send config data!');
86
+        console.log(JSON.stringify(e));
87
+    });*/
88
+  }
89
+});
90
+
82 91
 
83 92
 // Store location in Pebble app local storage
84 93
 //
85 94
 function storeLocation(position) {
86
-    var latitude = position.coords.latitude;
87
-    var longitude = position.coords.longitude;
88
-    var timestamp = position.timestamp;
89
-    localStorage.setItem("latitude", latitude);
90
-    localStorage.setItem("longitude", longitude);
91
-    localStorage.setItem("timestamp", timestamp);
92
-    // console.log("Stored location " + position.coords.latitude + ',' + position.coords.longitude);
95
+  var latitude = position.coords.latitude;
96
+  var longitude = position.coords.longitude;
97
+  var timestamp = position.timestamp;
98
+  localStorage.setItem("latitude", latitude);
99
+  localStorage.setItem("longitude", longitude);
100
+  localStorage.setItem("timestamp", timestamp);
101
+  // console.log("Stored location " + position.coords.latitude + ',' + position.coords.longitude);
93 102
 }
94 103
 
95 104
 // Get location from Pebble app local storage
96 105
 //
97 106
 function getLocation() {
98
-    if (localStorage.getItem("latitude") || localStorage.getItem("longitude") || localStorage.getItem("timestamp")) {
99
-        var la = localStorage.getItem("latitude");
100
-        var lo = localStorage.getItem("longitude");
101
-        var ti = localStorage.getItem("timestamp");
102
-        var co = { "latitude": la, "longitude": lo };
103
-        var pos = { "coords": co, "timestamp": ti };
104
-        // console.log("Stored location " + pos.co.la + ',' + pos.co.lo);
105
-        return pos;
106
-    } else {
107
-        return null;
108
-    }
107
+  if (localStorage.getItem("latitude") || localStorage.getItem("longitude") || localStorage.getItem("timestamp")) {
108
+    var la = localStorage.getItem("latitude");
109
+    var lo = localStorage.getItem("longitude");
110
+    var ti = localStorage.getItem("timestamp");
111
+    var co = { "latitude": la, "longitude": lo };
112
+    var pos = { "coords": co, "timestamp": ti };
113
+    // console.log("Stored location " + pos.co.la + ',' + pos.co.lo);
114
+    return pos;
115
+  } else {
116
+    return null;
117
+  }
109 118
 }
110 119
 
111 120
 // Get max speed of the run
112 121
 //
113 122
 function getMaxSpeed(lastSpeed) {
114
-    oldmax = localStorage.getItem("maxSpeed") || -1;
115
-    if (oldmax < lastSpeed) {
116
-        maxSpeed = lastSpeed
117
-    } else if (oldmax > lastSpeed) {
118
-        maxSpeed = oldmax
119
-    } else {
120
-        maxSpeed = oldmax
121
-    }
122
-    localStorage.setItem("maxSpeed", maxSpeed);
123
-    return maxSpeed
123
+  oldmax = localStorage.getItem("maxSpeed") || -1;
124
+  if (oldmax < lastSpeed) {
125
+    maxSpeed = lastSpeed
126
+  } else if (oldmax > lastSpeed) {
127
+    maxSpeed = oldmax
128
+  } else {
129
+    maxSpeed = oldmax
130
+  }
131
+  localStorage.setItem("maxSpeed", maxSpeed);
132
+  return maxSpeed
124 133
 }
125 134
 
126 135
 // split float number into an array of int (null returned instead of 0 for decimal)
127 136
 //
128 137
 function splitFloatNumber(num) {
129
-    const intStr = num.toString().split('.')[0];
130
-    const decimalStr = num.toString().split('.')[1];
131
-    return [Number(intStr), Number(decimalStr)];
138
+  const intStr = num.toString().split('.')[0];
139
+  const decimalStr = num.toString().split('.')[1];
140
+  return [Number(intStr), Number(decimalStr)];
132 141
 
133 142
 }
134 143
 
135 144
 // Build GPX headers
136 145
 //
137 146
 function GPXHeadersBuilder(timestamp, name, type) {
138
-    var headers = '<?xml version="1.0" encoding="UTF-8"?><gpx creator="Pebble with barometer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd" version="1.1" xmlns="http://www.topografix.com/GPX/1/1"><metadata><time>' + timestamp + '</time></metadata><trk><name>' + name + '</name><type>' + type + '</type><trkseg>';
139
-    var ret = localStorage.setItem("GPX", headers);
140
-    return true;
147
+  var headers = '<?xml version="1.0" encoding="UTF-8"?><gpx creator="Pebble with barometer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd" version="1.1" xmlns="http://www.topografix.com/GPX/1/1"><metadata><time>' + timestamp + '</time></metadata><trk><name>' + name + '</name><type>' + type + '</type><trkseg>';
148
+  var ret = localStorage.setItem("GPX", headers);
149
+  return true;
141 150
 }
142 151
 
143
-// Build GPX footer
152
+// Build GPX track point
144 153
 //
145 154
 function GPXtrkptBuilder(lat, lon, ele, timestamp) {
146
-    var GPX = localStorage.getItem("GPX");
147
-    var trkpt = '<trkpt lat="' + lat + '" lon="' + lon + '"><ele>' + ele + '</ele><time>' + timestamp + '</time></trkpt>';
148
-    localStorage.setItem("GPX", GPX + trkpt);
149
-    return true;
155
+  var GPX = localStorage.getItem("GPX");
156
+  var trkpt = '<trkpt lat="' + lat + '" lon="' + lon + '"><ele>' + ele + '</ele><time>' + timestamp + '</time></trkpt>';
157
+  localStorage.setItem("GPX", GPX + trkpt);
158
+  return true;
150 159
 }
151 160
 
152 161
 // Build GPX footer
153 162
 //
154 163
 function GPXfooterBuilder() {
155
-    var GPX = localStorage.getItem("GPX");
156
-    var footer = '</trkseg></trk></gpx>';
157
-    var ret = localStorage.setItem("GPX", GPX + footer);
158
-    //console.log("GPX closed : " + GPX + footer);
159
-    return ret;
164
+  var GPX = localStorage.getItem("GPX");
165
+  var footer = '</trkseg></trk></gpx>';
166
+  var ret = localStorage.setItem("GPX", GPX + footer);
167
+  //console.log("GPX closed : " + GPX + footer);
168
+  return ret;
160 169
 }
161 170
 
171
+//------------------------------------------
172
+// OAUTH functions
173
+//------------------------------------------
174
+
175
+function getTokens(code) {
176
+  // call to strava api to get tokens in exchange of temp code
177
+  // need to use strava.jonget.fr to proxy request and hide secret
178
+  var url = "https://www.strava.com/oauth/token?client_id=" + client_id + "&client_secret=" + client_secret + "&code=" + code + "&grant_type=authorization_code";
179
+  var xhr = new XMLHttpRequest();
180
+  xhr.timeout = 10000; // time in milliseconds
181
+
182
+  xhr.open("POST", url, false);
183
+
184
+  xhr.onload = function () {
185
+    //console.log('------xhr onloaded')
186
+    if (xhr.readyState === 4) {
187
+      console.log('------xhr request returned :', xhr.responseText);
188
+      response_json = JSON.parse(xhr.responseText);
189
+
190
+      var tokenjson = {
191
+        access_token: response_json.access_token,
192
+        refresh_token: response_json.refresh_token,
193
+        expiry: response_json.expires_at
194
+      };
195
+      localStorage.setItem("strava_tokens", JSON.stringify(tokenjson));
196
+
197
+    }
198
+  };
199
+
200
+  xhr.send();
201
+
202
+}
203
+
204
+function refreshTokens(refresh_token) {
205
+  // call to strava api to get tokens in exchange of refresh code
206
+  // need to use strava.jonget.fr to proxy request and hide secret
207
+  var url = "https://www.strava.com/oauth/token?client_id=" + client_id + "&client_secret=" + client_secret + "&refresh_token=" + refresh_token + "&grant_type=refresh_token";
208
+  var xhr = new XMLHttpRequest();
209
+  xhr.timeout = 10000; // time in milliseconds
210
+
211
+  xhr.open("POST", url, false);
212
+
213
+  xhr.onload = function () {
214
+    //console.log('------xhr onloaded')
215
+    if (xhr.readyState === 4) {
216
+      //console.log('------xhr request returned with ' + xhr.status);
217
+      response_json = JSON.parse(xhr.txt);
218
+
219
+      var tokenjson = {
220
+        access_token: response_json.access_token,
221
+        refresh_token: response_json.refresh_token,
222
+        expiry: response_json.expires_at
223
+      };
224
+      localStorage.setItem("strava_tokens", JSON.stringify(tokenjson));
225
+
226
+    }
227
+  };
228
+
229
+  xhr.send();
230
+
231
+}
162 232
 
163 233
 // Send GPX to Strava profile
164
-// TODO : get authentication creds from settings
165 234
 function SendToStrava() {
166
-    console.log('--- GPX upload to strava');
167
-    var gpxfile = localStorage.getItem("GPX");
168
-    // need to automate oAUTH
169
-    var bearer = "09f93068353f11f09d22059f1e8e42ef526949a5"
170
-    params = {
171
-        url: "https://www.strava.com/api/v3/uploads",
172
-        method: "POST",
173
-        data: { description: "desc", data_type: "gpx" },
174
-        files: { file: gpxfile },
175
-        authorization: "Bearer " + bearer,
176
-        callback: function(e) {
177
-            var message = "";
178
-            // what is 'r'
179
-            // what is 'e'
180
-            // what is 'o'
181
-            // what is 'z'
182
-            if (console.log(e.status + " - " + e.txt), 201 == e.status) {
183
-                message = "Your activity has been created";
184
-            } else if (400 == e.status) {
185
-                message = "An error has occurred. If you've already uploaded the current activity, please delete it in Strava.";
186
-            } else if (401 == e.status) {
187
-                message = "Error - Unauthorized. Please check your credentials in the settings.", o.setAccessToken("");
188
-            } else {
189
-                try {
190
-                    response_json = JSON.parse(e.txt)
191
-                    response_json.error ? (console.log("error:" + response_json.error), message = response_json.error, o.setAccessToken("")) : response_json.status && (console.log("status:" + response_json.status), z = response_json.status)
192
-                } catch (e) {
193
-                    console.log("Error log, " + e)
194
-                }
195
-            }
196
-            message && Pebble.showSimpleNotificationOnPebble("Ventoo SE - Strava", message)
197
-        }
198
-    }
199
-    var XHR = new XMLHttpRequest;
200
-    var n = this;
201
-    console.log(params.url);
202
-    XHR.open(params.method, params.url, !0);
203
-    var body = "";
204
-    var boundary = Math.random().toString().substring(2);
205
-    XHR.setRequestHeader("content-type", "multipart/form-data; charset=utf-8; boundary=" + boundary)
206
-    XHR.setRequestHeader("Authorization", params.authorization);
207
-    for (var i in params.data) body += "--" + boundary + '\r\nContent-Disposition: form-data; name="' + i + '"\r\n\r\n' + params.data[i] + "\r\n";
208
-    for (var i in params.files) body += "--" + boundary + '\r\nContent-Disposition: form-data; name="' + i + '" ; filename=test.gpx\r\n\r\n' + params.files[i] + "\r\n";
209
-    body += "--" + boundary + "--\r\n"
210
-
211
-    XHR.onreadystatechange = function() {
212
-        // what is 'n'
235
+  console.log('--- GPX upload to strava');
236
+  var gpxfile = localStorage.getItem("GPX");
237
+
238
+  var tokens = localStorage.getItem("strava_tokens");
239
+
240
+  var bearer = JSON.parse(tokens).access_token;
241
+  params = {
242
+    url: "https://www.strava.com/api/v3/uploads",
243
+    method: "POST",
244
+    data: { description: "desc", data_type: "gpx" },
245
+    files: { file: gpxfile },
246
+    authorization: "Bearer " + bearer,
247
+    callback: function (e) {
248
+      var message = "";
249
+      // what is 'r'
250
+      // what is 'e'
251
+      // what is 'o'
252
+      // what is 'z'
253
+      if (console.log(e.status + " - " + e.txt), 201 == e.status) {
254
+        message = "Your activity has been created";
255
+        localStorage.setItem("strava_uploaded", true);
256
+      } else if (400 == e.status) {
257
+        message = "An error has occurred. If you've already uploaded the current activity, please delete it in Strava.";
258
+      } else if (401 == e.status) {
259
+        message = "Error - Unauthorized. Please check your credentials in the settings.", o.setAccessToken("");
260
+      } else {
213 261
         try {
214
-            4 == XHR.readyState && (n.status = XHR.status, n.txt = XHR.responseText, n.xml = XHR.responseXML, params.callback && params.callback(n))
262
+          response_json = JSON.parse(e.txt)
263
+          response_json.error ? (console.log("error:" + response_json.error), message = response_json.error, o.setAccessToken("")) : response_json.status && (console.log("status:" + response_json.status), z = response_json.status)
215 264
         } catch (e) {
216
-            console.error("Error2 loading, ", e)
265
+          console.log("Error log, " + e)
217 266
         }
267
+      }
268
+      message && Pebble.showSimpleNotificationOnPebble("Ventoo SE - Strava", message)
269
+    }
270
+  }
271
+  var XHR = new XMLHttpRequest;
272
+  var n = this;
273
+  console.log(params.url);
274
+  XHR.open(params.method, params.url, !0);
275
+  var body = "";
276
+  var boundary = Math.random().toString().substring(2);
277
+  XHR.setRequestHeader("content-type", "multipart/form-data; charset=utf-8; boundary=" + boundary)
278
+  XHR.setRequestHeader("Authorization", params.authorization);
279
+  for (var i in params.data) body += "--" + boundary + '\r\nContent-Disposition: form-data; name="' + i + '"\r\n\r\n' + params.data[i] + "\r\n";
280
+  for (var i in params.files) body += "--" + boundary + '\r\nContent-Disposition: form-data; name="' + i + '" ; filename=test.gpx\r\n\r\n' + params.files[i] + "\r\n";
281
+  body += "--" + boundary + "--\r\n"
282
+
283
+  XHR.onreadystatechange = function () {
284
+    // what is 'n'
285
+    try {
286
+      4 == XHR.readyState && (n.status = XHR.status, n.txt = XHR.responseText, n.xml = XHR.responseXML, params.callback && params.callback(n))
287
+    } catch (e) {
288
+      console.error("Error2 loading, ", e)
218 289
     }
219
-    XHR.send(body)
290
+  }
291
+  XHR.send(body)
220 292
 }
221 293
 
222 294
 
223 295
 // Send GPX to web server (need configuration on serverside)
224 296
 // TODO : secure it ?
225 297
 function PostToWeb() {
226
-    console.log('--- GPX upload to custom web server');
227
-    var GPX = localStorage.getItem("GPX");
228
-    var url = JSON.parse(localStorage.getItem('clay-settings')).gpx_web_url + "?name=pebblegpx&type=application/gpx+xml";
229
-    var xhr = new XMLHttpRequest();
230
-    xhr.timeout = 10000; // time in milliseconds
231
-
232
-    xhr.open("POST", url, false);
233
-
234
-    //console.log('------ CSV / xhr opened')
235
-    xhr.onload = function() {
236
-        //console.log('------xhr onload')
237
-        if (xhr.readyState === 4) {
238
-            //console.log('------xhr request returned with ' + xhr.status);
239
-            //console.log(this.responseText);
240
-            if (xhr.status == 200) {
241
-                //console.log('--> HTTP 200');
242
-                return true;
243
-            } else {
244
-                //console.log('--> HTTP ' + xhr.status);
245
-                return false;
246
-            }
247
-        }
248
-    };
298
+  console.log('--- GPX upload to custom web server');
299
+  var GPX = localStorage.getItem("GPX");
300
+  var url = JSON.parse(localStorage.getItem('clay-settings')).gpx_web_url + "?name=pebblegpx&type=application/gpx+xml";
301
+  var xhr = new XMLHttpRequest();
302
+  xhr.timeout = 10000; // time in milliseconds
303
+
304
+  xhr.open("POST", url, false);
305
+
306
+  //console.log('------ CSV / xhr opened')
307
+  xhr.onload = function () {
308
+    //console.log('------xhr onloaded')
309
+    if (xhr.readyState === 4) {
310
+      //console.log('------xhr request returned with ' + xhr.status);
311
+      //console.log(this.responseText);
312
+      localStorage.setItem("custom_uploaded", true);
313
+      if (xhr.status == 200) {
314
+        //console.log('--> HTTP 200');
315
+        return true;
316
+      } else {
317
+        //console.log('--> HTTP ' + xhr.status);
318
+        return false;
319
+      }
320
+    }
321
+  };
249 322
 
250
-    //send CSV in body
251
-    xhr.send(GPX);
323
+  //send CSV in body
324
+  xhr.send(GPX);
252 325
 
253 326
 }
254 327
 
255 328
 // Send location to web server for instant location (no live tracking)
256 329
 // TODO : secure it ?
257 330
 function instantLocationUpdate(pos) {
258
-    console.log('--- Instant location update');
259
-    // console.log(" location is " + new_pos.coords.latitude + ',' + new_pos.coords.longitude + ' , acc. ' + new_pos.coords.accuracy);
260
-
261
-    var url = JSON.parse(localStorage.getItem('clay-settings')).ping_location_url + "?lat=" + pos.coords.latitude + "&long=" + pos.coords.longitude + "&acc=" + pos.coords.accuracy + "&timestamp=" + pos.timestamp;
262
-    var xhr = new XMLHttpRequest();
263
-    xhr.timeout = 10000; // time in milliseconds
264
-
265
-    xhr.open("POST", url);
266
-
267
-    //console.log('------ instant / xhr opened')
268
-    xhr.onload = function() {
269
-        //console.log('------xhr onload')
270
-        if (xhr.readyState === 4) {
271
-            //console.log('------xhr request returned with ' + xhr.status);
272
-            //console.log(this.responseText);
273
-            if (xhr.status == 200) {
274
-                //console.log('--> HTTP 200');
275
-                return true;
276
-            } else {
277
-                //console.log('--> HTTP ' + xhr.status);
278
-                return false;
279
-            }
280
-        }
281
-    };
331
+  console.log('--- Instant location update');
332
+  // console.log(" location is " + new_pos.coords.latitude + ',' + new_pos.coords.longitude + ' , acc. ' + new_pos.coords.accuracy);
333
+
334
+  var url = JSON.parse(localStorage.getItem('clay-settings')).ping_location_url + "?lat=" + pos.coords.latitude + "&long=" + pos.coords.longitude + "&acc=" + pos.coords.accuracy + "&timestamp=" + pos.timestamp;
335
+  var xhr = new XMLHttpRequest();
336
+  xhr.timeout = 10000; // time in milliseconds
337
+
338
+  xhr.open("POST", url);
339
+
340
+  //console.log('------ instant / xhr opened')
341
+  xhr.onload = function () {
342
+    //console.log('------xhr onloaded')
343
+    if (xhr.readyState === 4) {
344
+      //console.log('------xhr request returned with ' + xhr.status);
345
+      //console.log(this.responseText);
346
+      if (xhr.status == 200) {
347
+        //console.log('--> HTTP 200');
348
+        return true;
349
+      } else {
350
+        //console.log('--> HTTP ' + xhr.status);
351
+        return false;
352
+      }
353
+    }
354
+  };
282 355
 
283
-    //send without body
284
-    xhr.send();
356
+  //send without body
357
+  xhr.send();
285 358
 
286 359
 }
287 360
 
288 361
 // called in case of successful geoloc gathering and sends the coordinate to watch
289 362
 //
290 363
 function locationSuccess(new_pos) {
291
-    console.log('--- locationSuccess');
292
-    // console.log(" location is " + new_pos.coords.latitude + ',' + new_pos.coords.longitude + ' , acc. ' + new_pos.coords.accuracy);
364
+  console.log('--- locationSuccess');
365
+  // console.log(" location is " + new_pos.coords.latitude + ',' + new_pos.coords.longitude + ' , acc. ' + new_pos.coords.accuracy);
293 366
 
294
-    var prev_pos = getLocation();
295
-    storeLocation(new_pos);
296
-    if (prev_pos === null) {
297
-        console.log('--- start building gpx');
367
+  var prev_pos = getLocation();
368
+  storeLocation(new_pos);
369
+  if (prev_pos === null) {
370
+    console.log('--- start building gpx');
298 371
 
299
-        if (gpx_to_strava || gpx_to_web) {
300
-            // Start the GPX file
301
-            GPXHeadersBuilder(new Date(new_pos.timestamp).toISOString(), "test", "18");
302
-        }
303
-    } else {
304
-        //clear watch of new position to avoid overlap
305
-        //navigator.geolocation.clearWatch(geoloc_id);
306
-        //console.log('--- watch geoloc cleared');
307
-        //var speed = speed_from_distance_and_time(prev_pos, new_pos);
308
-
309
-        //get speed from geoloc API isntead of calculate it
310
-        // speed is initially in m/s, get it at km/h
311
-        if (new_pos.coords.speed === null) {
312
-            var speed = 0;
313
-        } else {
314
-            var speed = new_pos.coords.speed * 3.6;
315
-        }
316 372
 
317
-        // Prepare display on watch
318
-        // now it's only raw data
319
-        // init strings
320
-        var latitudeString = "";
321
-        var longitudeString = "";
322
-        var accuracyString = "";
323
-        var altitudeString = "";
324
-        var speedString = "";
325
-
326
-        //formating for precision and max size
327
-        latitudeString = new_pos.coords.latitude.toString().substring(0, 12);
328
-        longitudeString = new_pos.coords.longitude.toString().substring(0, 12);
329
-        accuracyString = new_pos.coords.accuracy.toString().substring(0, 4);
330
-        //console.log("split num : " + new_pos.coords.altitude);
331
-        altitudeString = splitFloatNumber(new_pos.coords.altitude)[0].toString().substring(0, 5);
332
-        timestampISO = new Date(new_pos.timestamp).toISOString();
333
-        //console.log("split num : " + speed);
334
-        if (isNaN(speed)) {
335
-            speedString = "---";
336
-        } else {
337
-            speedString = splitFloatNumber(speed)[0].toString().substring(0, 3) + "." + splitFloatNumber(speed)[1].toString().substring(0, 1);
338
-            if (speedString == "0.N") {
339
-                speedString = "0.0";
340
-            }
373
+    // Start the GPX file
374
+    GPXHeadersBuilder(new Date(new_pos.timestamp).toISOString(), "test", "18");
341 375
 
342
-            //console.log("split num : " + getMaxSpeed(speed));
343
-            maxSpeedString = splitFloatNumber(getMaxSpeed(speed))[0].toString().substring(0, 3);
344
-        }
376
+  } else {
377
+    //clear watch of new position to avoid overlap
378
+    //navigator.geolocation.clearWatch(geoloc_id);
379
+    //console.log('--- watch geoloc cleared');
380
+    //var speed = speed_from_distance_and_time(prev_pos, new_pos);
345 381
 
346
-        if (gpx_to_strava || gpx_to_web) {
347
-            //add a new datapoint to GPX file
348
-            GPXtrkptBuilder(latitudeString, longitudeString, altitudeString, timestampISO);
382
+    //get speed from geoloc API isntead of calculate it
383
+    // speed is initially in m/s, get it at km/h
384
+    if (new_pos.coords.speed === null) {
385
+      var speed = 0;
386
+    } else {
387
+      var speed = new_pos.coords.speed * 3.6;
388
+    }
349 389
 
350
-        }
390
+    // Prepare display on watch
391
+    // now it's only raw data
392
+    // init strings
393
+    var latitudeString = "";
394
+    var longitudeString = "";
395
+    var accuracyString = "";
396
+    var altitudeString = "";
397
+    var speedString = "";
398
+
399
+    //formating for precision and max size
400
+    latitudeString = new_pos.coords.latitude.toString().substring(0, 12);
401
+    longitudeString = new_pos.coords.longitude.toString().substring(0, 12);
402
+    accuracyString = new_pos.coords.accuracy.toString().substring(0, 4);
403
+    //console.log("split num : " + new_pos.coords.altitude);
404
+    altitudeString = splitFloatNumber(new_pos.coords.altitude)[0].toString().substring(0, 5);
405
+    timestampISO = new Date(new_pos.timestamp).toISOString();
406
+    //console.log("split num : " + speed);
407
+    if (isNaN(speed)) {
408
+      speedString = "---";
409
+    } else {
410
+      speedString = splitFloatNumber(speed)[0].toString().substring(0, 3) + "." + splitFloatNumber(speed)[1].toString().substring(0, 1);
411
+      if (speedString == "0.N") {
412
+        speedString = "0.0";
413
+      }
351 414
 
352
-        // Build message
353
-        message = "OK";
354
-        var dict = {
355
-            'accuracy': accuracyString,
356
-            'altitude': altitudeString,
357
-            'speed': speedString,
358
-            'max_speed': maxSpeedString,
359
-            'status': message
360
-        };
361
-
362
-        // Send the message
363
-        Pebble.sendAppMessage(dict, function() {
364
-            console.log('Message sent successfully: ' + JSON.stringify(dict));
365
-        }, function(e) {
366
-            console.log('Message (' + JSON.stringify(dict) + ') failed: ' + JSON.stringify(e));
367
-        });
415
+      //console.log("split num : " + getMaxSpeed(speed));
416
+      maxSpeedString = splitFloatNumber(getMaxSpeed(speed))[0].toString().substring(0, 3);
368 417
     }
369 418
 
419
+    //add a new datapoint to GPX file
420
+    GPXtrkptBuilder(latitudeString, longitudeString, altitudeString, timestampISO);
421
+
422
+
423
+
424
+    // Build message
425
+    message = "OK";
426
+    var dict = {
427
+      'accuracy': accuracyString,
428
+      'altitude': altitudeString,
429
+      'speed': speedString,
430
+      'max_speed': maxSpeedString,
431
+      'status': message
432
+    };
433
+
434
+    // Send the message
435
+    Pebble.sendAppMessage(dict, function () {
436
+      console.log('Message sent successfully: ' + JSON.stringify(dict));
437
+    }, function (e) {
438
+      console.log('Message (' + JSON.stringify(dict) + ') failed: ' + JSON.stringify(e));
439
+    });
440
+  }
441
+
370 442
 }
371 443
 
372 444
 function locationError(err) {
373 445
 
374
-    console.warn('location error (' + err.code + '): ' + err.message);
446
+  console.warn('location error (' + err.code + '): ' + err.message);
375 447
 
376 448
 }
377 449
 
378 450
 
379 451
 function get_coordinate() {
380
-    console.log('--- Starting regular getCurrentPosition loop using setInterval at 1 sec');
452
+  console.log('--- Starting regular getCurrentPosition loop using setInterval at 1 sec');
381 453
 
382
-    locationInterval = setInterval(function() {
383
-        navigator.geolocation.getCurrentPosition(locationSuccess, locationError, locationOptions);
384
-    }, 1000);
454
+  locationInterval = setInterval(function () {
455
+    navigator.geolocation.getCurrentPosition(locationSuccess, locationError, locationOptions);
456
+  }, 1000);
385 457
 
386
-    if (locate_me) {
387
-        instantLocationInterval = setInterval(function() {
388
-            navigator.geolocation.getCurrentPosition(instantLocationUpdate, locationError, locationOptions);
389
-        }, 60000);
390
-    }
458
+  if (locate_me) {
459
+    instantLocationInterval = setInterval(function () {
460
+      navigator.geolocation.getCurrentPosition(instantLocationUpdate, locationError, locationOptions);
461
+    }, 60000);
462
+  }
391 463
 
392 464
 }
393 465
 
394 466
 function init() {
395
-    // local storage init
396
-    gpx_to_strava = JSON.parse(localStorage.getItem('clay-settings')).strava_upload;
397
-    gpx_to_web = JSON.parse(localStorage.getItem('clay-settings')).gpx_web_enable;
398
-    locate_me = JSON.parse(localStorage.getItem('clay-settings')).ping_location_enable;
467
+  // local storage init
468
+  try {
469
+    //console.log("Clay settings = " + localStorage.getItem('clay-settings'));
470
+    gpx_to_strava = JSON.parse(localStorage.getItem('clay-settings')).strava_enabled;
471
+    gpx_to_web = JSON.parse(localStorage.getItem('clay-settings')).gpx_web_enabled;
472
+    locate_me = JSON.parse(localStorage.getItem('clay-settings')).ping_location_enabled;
473
+
474
+    console.log("Locate_me = " + locate_me);
475
+    console.log("Strava = " + gpx_to_strava);
476
+    console.log("Custom web = " + gpx_to_web);
399 477
 
400 478
     var ce = gpx_to_web;
401
-    var cu = localStorage.getItem("custom_enabled");
479
+    var cu = localStorage.getItem("custom_uploaded");
402 480
     var se = gpx_to_strava;
403
-    var su = localStorage.getItem("strava_enabled");
481
+    var su = localStorage.getItem("strava_uploaded");
482
+
483
+    //checking token freshness (expiry >4h)
484
+    var delay = (Date.now() + 14400000) / 1000
485
+    if (se) {
486
+      if (JSON.parse(localStorage.getItem("strava_tokens")).expiry < delay) {
487
+        console.log("Strava oAuth token expiring or expired, refreshing it")
488
+        refreshTokens(JSON.parse(localStorage.getItem("strava_tokens")).refresh_token);
489
+      } else {
490
+        console.log("token (" + JSON.parse(localStorage.getItem("strava_tokens")).access_token + ")valid for 4h min, continuing")
491
+      }
492
+    }
493
+  } catch (e) { }
404 494
 
405
-    if ((se && !su) || (ce && !cu)) {
406
-        //posting any missed XHR from previous ride session
407
-        if (ce) {
408
-            PostToWeb();
409
-        }
410
-        if (se) {
411
-            SendToStrava();
412
-        }
413
-    } else {
414
-        localStorage.setItem("GPX", "");
415
-        localStorage.setItem("maxSpeed", "");
416
-        localStorage.setItem("latitude", "");
417
-        localStorage.setItem("longitude", "");
418
-        localStorage.setItem("timestamp", "");
419
-        localStorage.setItem("custom_uploaded", false);
420
-        localStorage.setItem("strava_uploaded", false);
495
+  if ((se && !su) || (ce && !cu)) {
496
+    //posting any missed XHR from previous ride session
497
+    if (ce) {
498
+      PostToWeb();
421 499
     }
422
-    // clear any other var to do
423
-    clearInterval(locationInterval);
424
-    clearInterval(instantLocationInterval);
425
-    navigator.geolocation.getCurrentPosition(locationSuccess, locationError, firstlocationOptions);
500
+    if (se) {
501
+      SendToStrava();
502
+    }
503
+  } else {
504
+    localStorage.setItem("GPX", "");
505
+    localStorage.setItem("maxSpeed", "");
506
+    localStorage.setItem("latitude", "");
507
+    localStorage.setItem("longitude", "");
508
+    localStorage.setItem("timestamp", "");
509
+    localStorage.setItem("custom_uploaded", false);
510
+    localStorage.setItem("strava_uploaded", false);
511
+  }
512
+  // clear any other var to do
513
+  clearInterval(locationInterval);
514
+  clearInterval(instantLocationInterval);
515
+  navigator.geolocation.getCurrentPosition(null, locationError, firstlocationOptions);
426 516
 
427 517
 }
428 518
 
429 519
 // Get JS readiness events
430
-Pebble.addEventListener('ready', function(e) {
431
-    console.log('PebbleKit JS is ready');
432
-    // Update Watch on this
433
-    Pebble.sendAppMessage({ 'JSReady': 1 });
520
+Pebble.addEventListener('ready', function (e) {
521
+  console.log('PebbleKit JS is ready');
522
+  // Update Watch on this
523
+  Pebble.sendAppMessage({ 'JSReady': 1 });
434 524
 
435
-    init();
525
+  init();
436 526
 });
437 527
 
438 528
 // Get AppMessage events
439
-Pebble.addEventListener('appmessage', function(e) {
440
-    // Get the dictionary from the message
441
-    var dict = e.payload;
442
-    //console.log(dict[0].toString());
443
-    switch (dict[0]) {
444
-        case 'get':
445
-            get_coordinate();
446
-            break;
447
-        case 'exit':
448
-            clearInterval(instantLocationInterval);
449
-            clearInterval(locationInterval);
450
-            if (gpx_to_strava || gpx_to_web) {
451
-                //End GPX file
452
-                GPXfooterBuilder();
453
-                if (gpx_to_strava) {
454
-                    //send to strava through API
455
-                    SendToStrava();
456
-                }
457
-                if (gpx_to_web) {
458
-                    // send CSV to web server through API
459
-                    PostToWeb();
460
-                }
461
-            }
462
-            // Send the message
463
-            var dict = {
464
-                'status': "EXIT"
465
-            };
466
-            Pebble.sendAppMessage(dict, function() {
467
-                console.log('Message sent successfully: ' + JSON.stringify(dict));
468
-            }, function(e) {
469
-                console.log('Message (' + JSON.stringify(dict) + ') failed: ' + JSON.stringify(e));
470
-            });
471
-
472
-            break;
473
-        default:
474
-            console.log('Sorry. I don\'t understand your request :' + dict[0]);
475
-    }
529
+Pebble.addEventListener('appmessage', function (e) {
530
+  // Get the dictionary from the message
531
+  var dict = e.payload;
532
+  //console.log(dict[0].toString());
533
+  switch (dict[0]) {
534
+    case 'get':
535
+      get_coordinate();
536
+      break;
537
+    case 'exit':
538
+      clearInterval(instantLocationInterval);
539
+      clearInterval(locationInterval);
540
+      gpx_to_strava = JSON.parse(localStorage.getItem('clay-settings')).strava_enabled;
541
+      gpx_to_web = JSON.parse(localStorage.getItem('clay-settings')).gpx_web_enabled;
542
+      locate_me = JSON.parse(localStorage.getItem('clay-settings')).ping_location_enabled;
543
+
544
+      //End GPX file
545
+      GPXfooterBuilder();
546
+      if (gpx_to_strava) {
547
+        //send to strava through API
548
+        SendToStrava();
549
+      }
550
+      if (gpx_to_web) {
551
+        // send CSV to web server through API
552
+        PostToWeb();
553
+      }
554
+      if (locate_me) {
555
+        var prev_pos = getLocation();
556
+        instantLocationUpdate(prev_pos);
557
+      }
558
+
559
+      // Send the message
560
+      var dict = {
561
+        'status': "EXIT"
562
+      };
563
+      Pebble.sendAppMessage(dict, function () {
564
+        console.log('Message sent successfully: ' + JSON.stringify(dict));
565
+      }, function (e) {
566
+        console.log('Message (' + JSON.stringify(dict) + ') failed: ' + JSON.stringify(e));
567
+      });
568
+
569
+      break;
570
+    default:
571
+      console.log('Sorry. I don\'t understand your request :' + dict[0]);
572
+  }
476 573
 
477 574
 });
478 575
\ No newline at end of file