Skip to content

Commit e35fc4d

Browse files
committed
Update: The analytics service is anonymized to prevent leaking any user related data
1 parent 1176f65 commit e35fc4d

1 file changed

Lines changed: 75 additions & 7 deletions

File tree

app/scripts/background.js

Lines changed: 75 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,15 @@ arc.bg.getAppId = () => {
117117
});
118118
});
119119
};
120+
arc.bg.getAppAnonumousId = () => {
121+
return new Promise((resolve) => {
122+
chrome.storage.local.get({
123+
'appAnonymousId': null
124+
}, function(result) {
125+
resolve(result.appAnonymousId);
126+
});
127+
});
128+
};
120129
arc.bg.releaseChannel = () => {
121130
var manifest = chrome.runtime.getManifest();
122131
// jscs:disable
@@ -149,22 +158,81 @@ arc.bg.notifyBetaUpdate = () => {
149158
}
150159
});
151160
};
161+
/**
162+
* To ensure anynomous app usage the app is using browser's build in crypto functions.
163+
* It requires to generate some initial random data to encode a string.
164+
*
165+
* Generated values are not stored so they can't be used again. Clearing hashed app id
166+
* (anonumousId) can't be restored.
167+
*/
168+
arc.bg.getAninimizedId = () => {
169+
return arc.bg.getAppAnonumousId().then((anonymousId) => {
170+
if (anonymousId) {
171+
return anonymousId;
172+
}
173+
// The app id is kept locally and it's available to the app.
174+
// It was used to identify user data on server storage.
175+
// It's not used right now since there's no app's server data synchroznization
176+
// but it's a subject to change.
177+
let encodedDataBuffer;
178+
return arc.bg.getAppId()
179+
.then((appId) => {
180+
let encoder = new TextEncoder('utf-8');
181+
encodedDataBuffer = encoder.encode(appId);
182+
let aesAlgorithmKeyGen = {
183+
name: 'AES-CBC',
184+
length: 128
185+
};
186+
return window.crypto.subtle.generateKey(aesAlgorithmKeyGen, false, ['encrypt']);
187+
})
188+
.then((cryptoKey) => {
189+
let aesAlgorithmEncrypt = {
190+
name: 'AES-CBC',
191+
iv: window.crypto.getRandomValues(new Uint8Array(16))
192+
};
193+
return window.crypto.subtle.encrypt(aesAlgorithmEncrypt, cryptoKey, encodedDataBuffer);
194+
})
195+
.then((arrayBuffer) => {
196+
let view = new Uint8Array(arrayBuffer);
197+
let arr = Array.prototype.slice.call(view);
198+
arr = arr.map(function(item) {
199+
return String.fromCharCode(item);
200+
});
201+
return window.btoa(arr.join(''));
202+
})
203+
.then((base64) => {
204+
return new Promise((resolve) => {
205+
chrome.storage.local.set({
206+
appAnonymousId: base64
207+
}, function() {
208+
resolve(base64);
209+
});
210+
});
211+
});
212+
});
213+
};
152214
/**
153215
* Very base replacement for GA session counter.
154216
* According to T&C of GA users must have ability to disable GA in the app.
155-
* However usage stats are crutial for the app.
217+
* However usage (only usage which is # of app openings) stats are crutial for the app.
156218
* This function will send generated an nonymous ID to the app's backed to record the session.
157219
* This is the only information send to the backed (time and generated ID)
158220
*/
159221
arc.bg.recordSession = () => {
160-
arc.bg.getAppId().then((appId) => {
222+
arc.bg.getAninimizedId().then((aid) => {
161223
let d = new Date();
162-
let url = 'http://api.chromerestclient.com/analytics/record?ai=';
163-
url += appId + '&t=';
164-
url += d.getTime() + '&tz=';
165-
url += d.getTimezoneOffset();
224+
// let url = 'http://localhost:8080/analytics/record';
225+
let url = 'http://api.chromerestclient.com/analytics/record';
226+
let data = new FormData();
227+
data.append('aid', aid); // anonymousId
228+
data.append('t', d.getTime()); // time
229+
data.append('tz', d.getTimezoneOffset()); //timezone
230+
var headers = new Headers();
231+
headers.append('x-api-version', '2');
166232
fetch(url, {
167-
method: 'POST'
233+
method: 'POST',
234+
body: data,
235+
headers: headers
168236
}).catch(() => {});
169237
});
170238
};

0 commit comments

Comments
 (0)