diff --git a/src/Analytics.js b/src/Analytics.js index 1b4f45bc6b..5c39b48a35 100644 --- a/src/Analytics.js +++ b/src/Analytics.js @@ -14,25 +14,54 @@ limitations under the License. */ -import { getCurrentLanguage } from './languageHandler'; +import { getCurrentLanguage, _t, _td } from './languageHandler'; import PlatformPeg from './PlatformPeg'; -import SdkConfig from './SdkConfig'; +import SdkConfig, { DEFAULTS } from './SdkConfig'; +import Modal from './Modal'; +import sdk from './index'; + +function getRedactedHash() { + return window.location.hash.replace(/#\/(group|room|user)\/(.+)/, "#/$1/"); +} function getRedactedUrl() { - const redactedHash = window.location.hash.replace(/#\/(group|room|user)\/(.+)/, "#/$1/"); // hardcoded url to make piwik happy - return 'https://riot.im/app/' + redactedHash; + return 'https://riot.im/app/' + getRedactedHash(); } const customVariables = { - 'App Platform': 1, - 'App Version': 2, - 'User Type': 3, - 'Chosen Language': 4, - 'Instance': 5, - 'RTE: Uses Richtext Mode': 6, - 'Homeserver URL': 7, - 'Identity Server URL': 8, + 'App Platform': { + id: 1, + expl: _td('The platform you\'re on'), + }, + 'App Version': { + id: 2, + expl: _td('The version of Riot.im'), + }, + 'User Type': { + id: 3, + expl: _td('Whether or not you\'re logged in (we don\'t record your user name)'), + }, + 'Chosen Language': { + id: 4, + expl: _td('Your language of choice'), + }, + 'Instance': { + id: 5, + expl: _td('Which officially provided instance you are using, if any'), + }, + 'RTE: Uses Richtext Mode': { + id: 6, + expl: _td('Whether or not you\'re using the Richtext mode of the Rich Text Editor'), + }, + 'Homeserver URL': { + id: 7, + expl: _td('Your homeserver\'s URL'), + }, + 'Identity Server URL': { + id: 8, + expl: _td('Your identity server\'s URL'), + }, }; function whitelistRedact(whitelist, str) { @@ -40,9 +69,6 @@ function whitelistRedact(whitelist, str) { return ''; } -const whitelistedHSUrls = ["https://matrix.org"]; -const whitelistedISUrls = ["https://vector.im"]; - class Analytics { constructor() { this._paq = null; @@ -140,11 +166,16 @@ class Analytics { } _setVisitVariable(key, value) { - this._paq.push(['setCustomVariable', customVariables[key], key, value, 'visit']); + this._paq.push(['setCustomVariable', customVariables[key].id, key, value, 'visit']); } setLoggedIn(isGuest, homeserverUrl, identityServerUrl) { if (this.disabled) return; + + const config = SdkConfig.get(); + const whitelistedHSUrls = config.piwik.whitelistedHSUrls || DEFAULTS.piwik.whitelistedHSUrls; + const whitelistedISUrls = config.piwik.whitelistedISUrls || DEFAULTS.piwik.whitelistedISUrls; + this._setVisitVariable('User Type', isGuest ? 'Guest' : 'Logged In'); this._setVisitVariable('Homeserver URL', whitelistRedact(whitelistedHSUrls, homeserverUrl)); this._setVisitVariable('Identity Server URL', whitelistRedact(whitelistedISUrls, identityServerUrl)); @@ -154,6 +185,44 @@ class Analytics { if (this.disabled) return; this._setVisitVariable('RTE: Uses Richtext Mode', state ? 'on' : 'off'); } + + showDetailsModal() { + const Tracker = window.Piwik.getAsyncTracker(); + const rows = Object.values(customVariables).map((v) => Tracker.getCustomVariable(v.id)).filter(Boolean); + + const resolution = `${window.screen.width}x${window.screen.height}`; + + const ErrorDialog = sdk.getComponent('dialogs.ErrorDialog'); + Modal.createTrackedDialog('Analytics Details', '', ErrorDialog, { + title: _t('Analytics'), + description:
+
+ { _t('The information being sent to us to help make Riot.im better includes:') } +
+ + { rows.map((row) => + + + ) } +
{ _t(customVariables[row[0]].expl) }{ row[1] }
+
+
+ { _t('We also record each page you use in the app (currently ), your User Agent' + + ' () and your device resolution ().', + {}, + { + CurrentPageHash: { getRedactedHash() }, + CurrentUserAgent: { navigator.userAgent }, + CurrentDeviceResolution: { resolution }, + }, + ) } + + { _t('Where this page includes identifiable information, such as a room, ' + + 'user or group ID, that data is removed before being sent to the server.') } +
+
, + }); + } } if (!global.mxAnalytics) { diff --git a/src/SdkConfig.js b/src/SdkConfig.js index 8df725a913..64bf21ecf8 100644 --- a/src/SdkConfig.js +++ b/src/SdkConfig.js @@ -21,6 +21,13 @@ const DEFAULTS = { integrations_rest_url: "https://scalar.vector.im/api", // Where to send bug reports. If not specified, bugs cannot be sent. bug_report_endpoint_url: null, + + piwik: { + url: "https://piwik.riot.im/", + whitelistedHSUrls: ["https://matrix.org"], + whitelistedISUrls: ["https://vector.im", "https://matrix.org"], + siteId: 1, + }, }; class SdkConfig { @@ -45,3 +52,4 @@ class SdkConfig { } module.exports = SdkConfig; +module.exports.DEFAULTS = DEFAULTS; diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js index 92cbb6e57e..b1eedd1a90 100644 --- a/src/components/structures/UserSettings.js +++ b/src/components/structures/UserSettings.js @@ -812,6 +812,12 @@ module.exports = React.createClass({

{ _t('Analytics') }

{ _t('Riot collects anonymous analytics to allow us to improve the application.') } +
+ { _t('Privacy is important to us, so we don\'t collect any personal' + + ' or identifiable data for our analytics.') } +
+ { _t('Learn more about how we use analytics.') } +
{ ANALYTICS_SETTINGS.map( this._renderDeviceSetting ) }
; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 81bc1f3d2d..0d686ad490 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -842,6 +842,8 @@ "Report it": "Report it", "Analytics": "Analytics", "Riot collects anonymous analytics to allow us to improve the application.": "Riot collects anonymous analytics to allow us to improve the application.", + "Privacy is important to us, so we don't collect any personal or identifiable data for our analytics.": "Privacy is important to us, so we don't collect any personal or identifiable data for our analytics.", + "Learn more about how we use analytics.": "Learn more about how we use analytics.", "Labs": "Labs", "These are experimental features that may break in unexpected ways": "These are experimental features that may break in unexpected ways", "Use with caution": "Use with caution", @@ -965,5 +967,16 @@ "This process allows you to import encryption keys that you had previously exported from another Matrix client. You will then be able to decrypt any messages that the other client could decrypt.": "This process allows you to import encryption keys that you had previously exported from another Matrix client. You will then be able to decrypt any messages that the other client could decrypt.", "The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.": "The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.", "File to import": "File to import", - "Import": "Import" + "Import": "Import", + "The information being sent to us to help make Riot.im better includes:": "The information being sent to us to help make Riot.im better includes:", + "We also record each page you use in the app (currently ), your User Agent () and your device resolution ().": "We also record each page you use in the app (currently ), your User Agent () and your device resolution ().", + "Where this page includes identifiable information, such as a room, user or group ID, that data is removed before being sent to the server.": "Where this page includes identifiable information, such as a room, user or group ID, that data is removed before being sent to the server.", + "The platform you're on": "The platform you're on", + "The version of Riot.im": "The version of Riot.im", + "Whether or not you're logged in (we don't record your user name)": "Whether or not you're logged in (we don't record your user name)", + "Your language of choice": "Your language of choice", + "Which officially provided instance you are using, if any": "Which officially provided instance you are using, if any", + "Whether or not you're using the Richtext mode of the Rich Text Editor": "Whether or not you're using the Richtext mode of the Rich Text Editor", + "Your homeserver's URL": "Your homeserver's URL", + "Your identity server's URL": "Your identity server's URL" }