├── .gitignore ├── LICENSE.md ├── README.md ├── background.html ├── css └── transfer.css ├── environment ├── dev │ └── manifest.json ├── production │ └── manifest.json └── test │ └── manifest.json ├── icons ├── Horizontal outline lockup.svg ├── Horizontal solid green lockup Copy.svg ├── Horizontal solid green lockup.svg ├── Outline Mark.svg ├── Outline Vertical Lockup.svg ├── Outline_Mark.png ├── Solid Green Vertical Lockup.svg ├── Solid Mono Vertical Lockup.svg ├── Solid green mark.svg ├── Solid mono mark.svg ├── Wordmark only.svg ├── error_mark.png ├── error_mark_128.png ├── error_mark_19.png ├── error_mark_38.png ├── error_mark_48.png ├── error_mark_96.png ├── green_mark.png ├── green_mark_128.png ├── green_mark_19.png ├── green_mark_38.png ├── green_mark_48.png ├── green_mark_96.png ├── mono_mark.png ├── mono_mark_19.png ├── mono_mark_38.png ├── outline_mark_19.png ├── outline_mark_38.png ├── outline_mark_filter_19.png └── outline_mark_filter_38.png ├── js ├── backgroundScript.js ├── browserUtils.js ├── communityHelper.js ├── configManager.js ├── configs │ ├── apiCall.json │ ├── community.json │ ├── config.json │ ├── memberManager.json │ ├── onboarding.json │ ├── stream.json │ ├── stream.sample.json │ └── swashAPI.json ├── content_scripts │ ├── content_script.js │ ├── context_script.js │ ├── task_script.js │ └── transfer_script.js ├── dataHandler.js ├── databaseHelper.js ├── filterUtils.js ├── functions.js ├── functions │ ├── apiCall.js │ ├── browsing.js │ ├── content.js │ ├── context.js │ ├── task.js │ └── transfer.js ├── internalFilters.js ├── loader.js ├── manifest.js ├── memberManager.js ├── menu.js ├── modules │ ├── Beauty │ │ ├── bathandbodyworks │ │ │ ├── config.json │ │ │ └── content.json │ │ ├── faberlic │ │ │ ├── config.json │ │ │ └── content.json │ │ ├── oriflame │ │ │ ├── config.json │ │ │ └── content.json │ │ ├── sephora │ │ │ ├── config.json │ │ │ └── content.json │ │ └── ulta │ │ │ ├── config.json │ │ │ └── content.json │ ├── General │ │ └── surfing │ │ │ ├── browsing.json │ │ │ ├── config.json │ │ │ └── content.json │ ├── Music │ │ └── youtube │ │ │ ├── browsing.json │ │ │ ├── config.json │ │ │ └── content.json │ ├── News │ │ ├── bbc │ │ │ ├── config.json │ │ │ └── content.json │ │ ├── cnn │ │ │ ├── config.json │ │ │ └── content.json │ │ ├── dailymail │ │ │ ├── config.json │ │ │ └── content.json │ │ ├── globo │ │ │ ├── config.json │ │ │ └── content.json │ │ ├── msn │ │ │ ├── config.json │ │ │ └── content.json │ │ ├── uol │ │ │ ├── config.json │ │ │ └── content.json │ │ ├── yahoo │ │ │ ├── config.json │ │ │ └── content.json │ │ └── yahooNews │ │ │ ├── config.json │ │ │ └── content.json │ ├── Search │ │ ├── aol │ │ │ ├── browsing.json │ │ │ ├── config.json │ │ │ └── content.json │ │ ├── ask │ │ │ ├── browsing.json │ │ │ ├── config.json │ │ │ └── content.json │ │ ├── baidu │ │ │ ├── browsing.json │ │ │ ├── config.json │ │ │ └── content.json │ │ ├── bing │ │ │ ├── browsing.json │ │ │ ├── config.json │ │ │ └── content.json │ │ ├── duckduckgo │ │ │ ├── browsing.json │ │ │ ├── config.json │ │ │ └── content.json │ │ ├── google │ │ │ ├── browsing.json │ │ │ ├── config.json │ │ │ └── content.json │ │ └── yahoo │ │ │ ├── browsing.json │ │ │ ├── config.json │ │ │ └── content.json │ ├── Shopping │ │ ├── amazon │ │ │ ├── browsing.json │ │ │ ├── config.json │ │ │ └── content.json │ │ ├── ebay │ │ │ ├── config.json │ │ │ └── content.json │ │ ├── etsy │ │ │ ├── config.json │ │ │ └── content.json │ │ ├── flipkart │ │ │ ├── config.json │ │ │ └── content.json │ │ ├── target │ │ │ ├── config.json │ │ │ └── content.json │ │ └── walmart │ │ │ ├── config.json │ │ │ └── content.json │ └── Social │ │ ├── facebook │ │ ├── browsing.json │ │ └── config.json │ │ └── twitter │ │ ├── browsing.json │ │ └── config.json ├── onboarding.js ├── pageAction.js ├── privacyUtils.js ├── storageHelper.js ├── stream.js ├── swashApiHelper.js ├── utils.js └── webHelper.js ├── lib ├── 3box.js ├── browser-polyfill.js ├── ethers.js ├── identity-wallet.js ├── jsonpath.js ├── jsonpointer.js ├── jsontokens.js ├── jsstore.js ├── jsstore.worker.js ├── sha256.js └── streamr-client.js ├── manifest.json ├── popup ├── css │ └── all.css ├── fonts │ ├── .DS_Store │ ├── roboto-mono-v7-latin-500.eot │ ├── roboto-mono-v7-latin-500.svg │ ├── roboto-mono-v7-latin-500.ttf │ ├── roboto-mono-v7-latin-500.woff │ ├── roboto-mono-v7-latin-500.woff2 │ ├── roboto-mono-v7-latin-regular.eot │ ├── roboto-mono-v7-latin-regular.svg │ ├── roboto-mono-v7-latin-regular.ttf │ ├── roboto-mono-v7-latin-regular.woff │ ├── roboto-mono-v7-latin-regular.woff2 │ ├── roboto-v20-latin-500.eot │ ├── roboto-v20-latin-500.svg │ ├── roboto-v20-latin-500.ttf │ ├── roboto-v20-latin-500.woff │ ├── roboto-v20-latin-500.woff2 │ ├── roboto-v20-latin-regular.eot │ ├── roboto-v20-latin-regular.svg │ ├── roboto-v20-latin-regular.ttf │ ├── roboto-v20-latin-regular.woff │ └── roboto-v20-latin-regular.woff2 ├── popup.html ├── svg │ ├── Data_default.svg │ ├── Data_hover.svg │ ├── Help_hover.svg │ ├── Icons _ Progress _ Loading finished _ small.svg │ ├── Message _ Nortification _ error state .png │ ├── Settings_default.svg │ ├── Settings_hover.svg │ ├── cog.svg │ ├── filter-active.png │ ├── filter-default.png │ ├── filter-hover.png │ ├── filter-mono.png │ ├── navigation-menu-3.svg │ ├── question-circle.svg │ └── small.svg └── webfonts │ ├── fa-brands-400.eot │ ├── fa-brands-400.svg │ ├── fa-brands-400.ttf │ ├── fa-brands-400.woff │ ├── fa-brands-400.woff2 │ ├── fa-regular-400.eot │ ├── fa-regular-400.svg │ ├── fa-regular-400.ttf │ ├── fa-regular-400.woff │ ├── fa-regular-400.woff2 │ ├── fa-solid-900.eot │ ├── fa-solid-900.svg │ ├── fa-solid-900.ttf │ ├── fa-solid-900.woff │ └── fa-solid-900.woff2 ├── swash.sh └── test ├── css └── mocha.css ├── js ├── lib │ ├── chai.js │ ├── expect.js │ ├── mocha-run.js │ ├── mocha-setup.js │ └── mocha.js └── unit │ ├── communityhelper.test.js │ ├── databaseHelper.test.js │ ├── filterUtils.test.js │ ├── privacyUtils.test.js │ ├── storageHelper.test.js │ └── utils.test.js └── test.html /.gitignore: -------------------------------------------------------------------------------- 1 | dashboard/ 2 | chrome-artifacts/ 3 | web-ext-artifacts/ 4 | js/streamConfig.js 5 | js/configs/streamConfig.json 6 | 7 | /.idea/ 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Swash 2 | Swash is a browser extension for collecting and aggregating your browsing activities. This extension collects information about your browsing activities and gives you, ability to sell your data on the [Streamr Marketplace](https://streamr.network/marketplace). 3 | 4 | The extension consists of some modules. Each module has some Data Collectors and each Data Collector is responsible for collecting a specific data regarding its module. 5 | A Data Collector collects data using one of these methods: 6 | * Running a JavaScript code in the context of a specific page 7 | * Calling APIs on behalf of you 8 | * Capturing requests sent to/responses received from a specific domain 9 | * Reading your browser information 10 | 11 | We provide you with certain controls and choices regarding the data collected on your browser: 12 | * **Enabling/Disabling Swash**. You are able to enable/disable the Swash extension. When the extension is disabled nothing will be collected by the extension. 13 | * **Enabling/Disabling modules**. You are able to enable/disable each module of the Swash 14 | separately. When a module is disabled none of its collectors will collect data. 15 | * **Enabling/Disabling collectors**. You are able to enable/disable each collector of a module. When a collector is disabled it does not collect data. 16 | * **Delay on sending data**. You are able to make custom delay on sending data. It helps you watch data before being sent to the stream and it gives you the ability to cancel any data sending action. 17 | * **Text masking**. This feature allows you to actively mask specific text (characters, digits, single words or combination of them) within the data being captured and shared via the extension. This allows you to cover sensitive information that might be present, for example, within Facebook or Twitter posts or, less probable, search queries. One could for example add any variation of his/her own name, phone number, email, address, close people names etc. 18 | * **Exclude URLs**. This option allows you to specify which URLs you would like to exclude from data collection for all modules. You can use different expressions to exclude an exact match URL, an entire subsection of a URL path or even more advanced rules. Rules applied for this feature will supersede any module’s internal logic, so you can have peace of mind that anything applied correctly here will be followed by all modules. 19 | * **Data Privacy**. We provide you with a privacy mechanism to ensure the privacy of data getting collected by modules. The mechanism works based on the data type and the privacy level. The table below 20 | shows how the privacy mechanism transforms the data based on the data type: 21 | 22 | 23 | | Data Type | Lowest Privacy | Medium Privacy | High Privacy | 24 | |------------|----------------|----------------------------------------|---------------------------------------------------| 25 | | URL | No changes | Global masking path name | Remove path name | 26 | | Time | No changes | Remove hours | Remove months | 27 | | TimeString | No changes | Remove hours | Remove months | 28 | | Text | No changes | Replace defined masking texts with '*' | Remove text if it contains defined masking texts data | 29 | | Id | No changes | Global masking | Nullify | 30 | | UserInfo | No changes | Global masking | Nullify | 31 | | UserAttr | No changes | Global masking | Nullify | 32 | 33 | 34 | 35 | 36 | ## Getting Started 37 | 38 | These instructions will get you a copy of the project up and running on your local machine for development and testing purposes. 39 | 40 | ### Prerequisites 41 | 42 | The following applications are required to be installed and configured before you build Swash. 43 | 44 | ### Firefox >= 48 45 | A Firefox with version at least 48 is required to be installed on your system. 46 | 47 | ### Node.js 48 | You can download the Node.js source code or a pre-built installer for your platform from this [link](https://nodejs.org/en/download/) 49 | 50 | #### web-ext 51 | web-ext is a node-based application that you install with the nodejs/npm tool. Install web-ext using the following command: 52 | 53 | ``` 54 | npm install --global web-ext 55 | ``` 56 | To test whether the installation worked run the following command, which displays the web-ext version number: 57 | 58 | ``` 59 | web-ext --version 60 | ``` 61 | 62 | ### Swash development 63 | 64 | Swash extension consists of two separate projects: 65 | * *swash-ui*: This project has been developed using React and provides user interface for the extension 66 | * *swash*: This project is the source code for the extension engine 67 | 68 | *swash-ui* project should be built and copied to the */dashboard* before you build *swash* project. The instruction for building *swash-ui* can be found [here](https://github.com/swashapp/swash-ui) 69 | 70 | #### Build instruction for swash 71 | 72 | ``` 73 | git clone https://github.com/swashapp/swash.git 74 | cd swash 75 | cp js/streamConfig.sample.js js/streamConfig.js 76 | ``` 77 | Open streamConfig.js file and replace stream ids and API keys with your own. Then copy the built files from *swash-ui build* directory to */dashboard*. Now, you can build the extension. 78 | 79 | ``` 80 | ./swash.sh build 81 | ``` 82 | 83 | #### Executing test units 84 | 85 | In order to run *swash* test units, run this command: 86 | 87 | ``` 88 | ./swash.sh test 89 | ``` 90 | Then open a new tab. Test units will be started automatically. 91 | 92 | #### Running Swash 93 | 94 | This command starts Firefox and loads Swash temporarily in the browser: 95 | 96 | ``` 97 | ./swash.sh run 98 | ``` 99 | 100 | ## License 101 | 102 | This project is licensed under the Attribution-NonCommercial-ShareAlike 4.0 International License - see the [LICENSE.md](LICENSE.md) file for details 103 | -------------------------------------------------------------------------------- /background.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /css/transfer.css: -------------------------------------------------------------------------------- 1 | .showSwashMe{ 2 | display: block !important; 3 | position: fixed !important; 4 | } 5 | 6 | #swashMe img{ 7 | cursor: pointer; 8 | width: 30px; 9 | height: 30px; 10 | opacity: 0.2; 11 | } 12 | 13 | #swashMe:hover img{ 14 | opacity: 1; 15 | transform: scale(1.05); 16 | } 17 | 18 | 19 | @keyframes cssAnimation { 20 | to { 21 | width:0; 22 | height:0; 23 | overflow:hidden; 24 | } 25 | } 26 | @-webkit-keyframes cssAnimation { 27 | to { 28 | width:0; 29 | height:0; 30 | visibility:hidden; 31 | } 32 | } -------------------------------------------------------------------------------- /environment/dev/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "applications": { 3 | "gecko": { 4 | "id": "authsaz@gmail.com" 5 | } 6 | }, 7 | 8 | "background": { 9 | "page": "background.html" 10 | }, 11 | 12 | "browser_action": { 13 | "browser_style": false, 14 | "default_icon": { 15 | "19": "icons/green_mark_19.png", 16 | "38": "icons/green_mark_38.png" 17 | }, 18 | "default_title": "Swash" 19 | }, 20 | 21 | "description": "Get paid for your data as you browse the web. Gain control and help create a better, more dignified internet.", 22 | 23 | "icons": { 24 | "48": "icons/green_mark_48.png", 25 | "96": "icons/green_mark_96.png", 26 | "128": "icons/green_mark_128.png" 27 | }, 28 | 29 | "manifest_version": 2, 30 | 31 | "name": "Swash", 32 | 33 | "homepage_url": "https://swashapp.io/", 34 | 35 | "permissions": ["clipboardRead","storage","bookmarks", "tabs", "webRequest", "", "webRequestBlocking", "downloads"], 36 | 37 | "content_security_policy": "script-src 'self' https://www.youtube.com/ https://s.ytimg.com/; object-src 'self';", 38 | 39 | "version": "1.3.2" 40 | } 41 | -------------------------------------------------------------------------------- /environment/production/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "background": { 3 | "page": "background.html" 4 | }, 5 | 6 | "browser_action": { 7 | "browser_style": false, 8 | "default_icon": { 9 | "19": "icons/green_mark_19.png", 10 | "38": "icons/green_mark_38.png" 11 | }, 12 | "default_title": "Swash" 13 | }, 14 | 15 | "description": "Get paid for your data as you browse the web. Gain control and help create a better, more dignified internet.", 16 | 17 | "icons": { 18 | "48": "icons/green_mark_48.png", 19 | "96": "icons/green_mark_96.png", 20 | "128": "icons/green_mark_128.png" 21 | }, 22 | 23 | "manifest_version": 2, 24 | 25 | "name": "Swash", 26 | 27 | "homepage_url": "https://swashapp.io/", 28 | 29 | "permissions": ["clipboardRead","storage","bookmarks", "tabs", "webRequest", "", "webRequestBlocking", "downloads"], 30 | 31 | "content_security_policy": "script-src 'self' https://www.youtube.com/ https://s.ytimg.com/; object-src 'self';", 32 | 33 | "version": "1.3.2" 34 | } 35 | -------------------------------------------------------------------------------- /environment/test/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "applications": { 3 | "gecko": { 4 | "id": "authsaz@gmail.com" 5 | } 6 | }, 7 | 8 | "background": { 9 | "page": "background.html" 10 | }, 11 | 12 | "chrome_url_overrides" : { 13 | "newtab": "test/test.html" 14 | }, 15 | 16 | "description": "Get paid for your data as you browse the web. Gain control and help create a better, more dignified internet.", 17 | 18 | "icons": { 19 | "48": "icons/green_mark_48.png", 20 | "96": "icons/green_mark_96.png", 21 | "128": "icons/green_mark_128.png" 22 | }, 23 | 24 | "manifest_version": 2, 25 | 26 | "name": "Swash", 27 | 28 | "homepage_url": "https://swashapp.io/", 29 | 30 | "permissions": ["clipboardRead","storage","bookmarks", "tabs", "webRequest", "", "webRequestBlocking", "downloads"], 31 | 32 | "content_security_policy": "script-src 'self' https://www.youtube.com/ https://s.ytimg.com/; object-src 'self';", 33 | 34 | "version": "1.3.2" 35 | } 36 | -------------------------------------------------------------------------------- /icons/Outline Mark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | DD98D5AF-51C9-4517-9377-AA4DE5210ACE@1.00x 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /icons/Outline_Mark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/icons/Outline_Mark.png -------------------------------------------------------------------------------- /icons/Solid green mark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | B773DD30-5DAF-4BA9-A940-99A9D5163DD6@1.00x 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /icons/Solid mono mark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CC71A012-2041-4588-92CA-1ACCC3D92288@1.00x 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /icons/Wordmark only.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | A0CC2006-6FE0-42E3-A092-B622B7652035@1.00x 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /icons/error_mark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/icons/error_mark.png -------------------------------------------------------------------------------- /icons/error_mark_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/icons/error_mark_128.png -------------------------------------------------------------------------------- /icons/error_mark_19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/icons/error_mark_19.png -------------------------------------------------------------------------------- /icons/error_mark_38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/icons/error_mark_38.png -------------------------------------------------------------------------------- /icons/error_mark_48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/icons/error_mark_48.png -------------------------------------------------------------------------------- /icons/error_mark_96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/icons/error_mark_96.png -------------------------------------------------------------------------------- /icons/green_mark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/icons/green_mark.png -------------------------------------------------------------------------------- /icons/green_mark_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/icons/green_mark_128.png -------------------------------------------------------------------------------- /icons/green_mark_19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/icons/green_mark_19.png -------------------------------------------------------------------------------- /icons/green_mark_38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/icons/green_mark_38.png -------------------------------------------------------------------------------- /icons/green_mark_48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/icons/green_mark_48.png -------------------------------------------------------------------------------- /icons/green_mark_96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/icons/green_mark_96.png -------------------------------------------------------------------------------- /icons/mono_mark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/icons/mono_mark.png -------------------------------------------------------------------------------- /icons/mono_mark_19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/icons/mono_mark_19.png -------------------------------------------------------------------------------- /icons/mono_mark_38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/icons/mono_mark_38.png -------------------------------------------------------------------------------- /icons/outline_mark_19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/icons/outline_mark_19.png -------------------------------------------------------------------------------- /icons/outline_mark_38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/icons/outline_mark_38.png -------------------------------------------------------------------------------- /icons/outline_mark_filter_19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/icons/outline_mark_filter_19.png -------------------------------------------------------------------------------- /icons/outline_mark_filter_38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/icons/outline_mark_filter_38.png -------------------------------------------------------------------------------- /js/backgroundScript.js: -------------------------------------------------------------------------------- 1 | import {browserUtils} from "./browserUtils.js"; 2 | import {configManager} from "./configManager.js"; 3 | import {storageHelper} from "./storageHelper.js" 4 | import {databaseHelper} from "./databaseHelper.js" 5 | import {privacyUtils} from "./privacyUtils.js" 6 | import {apiCall} from "./functions/apiCall.js" 7 | import {loader} from "./loader.js" 8 | import {content} from "./functions/content.js" 9 | import {dataHandler} from "./dataHandler.js" 10 | import {context} from "./functions/context.js" 11 | import {communityHelper} from "./communityHelper.js" 12 | import {task} from "./functions/task.js" 13 | import {pageAction} from "./pageAction.js" 14 | import {transfer} from "./functions/transfer.js" 15 | import {onboarding} from "./onboarding.js" 16 | import {memberManager} from "./memberManager.js" 17 | import {swashApiHelper} from "./swashApiHelper.js" 18 | 19 | 20 | let isConfigReady = false; 21 | let tryCount = 0; 22 | 23 | function initConfigs() { 24 | memberManager.init(); 25 | dataHandler.init(); 26 | communityHelper.init(); 27 | onboarding.init(); 28 | apiCall.init(); 29 | swashApiHelper.init(); 30 | loader.initConfs(); 31 | } 32 | 33 | 34 | async function installSwash(info) { 35 | console.log("Start installing...") 36 | if(!isConfigReady) { 37 | console.log("Configuration files is not ready yet, will try install it later") 38 | if(tryCount < 120) { 39 | setTimeout(() => installSwash(info), 1000) 40 | tryCount++ 41 | return; 42 | } 43 | console.log("Configuration files couldn't be loaded successfully. Installation aborted"); 44 | return; 45 | } 46 | tryCount = 0; 47 | 48 | await configManager.importAll(); 49 | initConfigs(); 50 | if (info.reason === "update" || info.reason === "install") { 51 | await loader.createDBIfNotExist(); 52 | const isNeeded = await onboarding.isNeededOnBoarding(); 53 | if (isNeeded) { 54 | onboarding.openOnBoarding(); 55 | } else { 56 | await loader.install(); 57 | await loader.onInstalled(); 58 | } 59 | } 60 | } 61 | 62 | 63 | 64 | /* *** 65 | This function will invoke on: 66 | 1. update firefox 67 | 2. install add-on 68 | 3. update add-on 69 | */ 70 | browser.runtime.onInstalled.addListener(installSwash); 71 | 72 | browserUtils.getPlatformInfo().then(info => { 73 | browserUtils.isMobileDevice().then(res => { 74 | if (res) { 75 | browser.browserAction.onClicked.addListener(async () => 76 | browser.tabs.create({url: '/dashboard/index.html#/Settings',}) 77 | ); 78 | } else { 79 | browser.browserAction.setPopup({popup: 'popup/popup.html',}); 80 | } 81 | }) 82 | }); 83 | 84 | configManager.loadAll().then(async () => { 85 | console.log("Start loading...") 86 | 87 | //Now the configuration is avaliable 88 | initConfigs(); 89 | isConfigReady = true; 90 | 91 | 92 | /* Set popup menu for desktop versions */ 93 | 94 | 95 | /* *** 96 | Each content script, after successful injection on a page, will send a message to background script to request data. 97 | This part handles such requests. 98 | */ 99 | browser.runtime.onMessage.addListener((message, sender, sendResponse) => { 100 | 101 | if (sender.tab) 102 | message.params.push(sender.tab.id); 103 | let objList = { 104 | storageHelper: storageHelper, 105 | databaseHelper: databaseHelper, 106 | privacyUtils: privacyUtils, 107 | apiCall: apiCall, 108 | loader: loader, 109 | content: content, 110 | dataHandler: dataHandler, 111 | context: context, 112 | task: task, 113 | communityHelper: communityHelper, 114 | pageAction: pageAction, 115 | transfer: transfer, 116 | onboarding: onboarding, 117 | swashApiHelper: swashApiHelper, 118 | configManager: configManager 119 | }; 120 | sendResponse(objList[message.obj][message.func](...message.params)); 121 | }); 122 | 123 | 124 | 125 | /* *** 126 | If UI has changed a config in data storage, a reload should be performed. 127 | UI will modify data storage directly. 128 | */ 129 | //browser.storage.onChanged.addListener(loader.reload); 130 | 131 | /* *** 132 | After a successful load of add-on, 133 | the main loop will start. 134 | */ 135 | storageHelper.retrieveConfigs().then(confs => { 136 | if (confs) { 137 | loader.onInstalled(); 138 | } 139 | }); 140 | 141 | }) 142 | -------------------------------------------------------------------------------- /js/browserUtils.js: -------------------------------------------------------------------------------- 1 | var browserUtils = (function() { 2 | function getUserAgent() 3 | { 4 | return navigator.userAgent; 5 | } 6 | 7 | function getAllInstalledPlugins() 8 | { 9 | /*return browser.management.getAll();*/ 10 | } 11 | 12 | function getBrowserLanguage() 13 | { 14 | return navigator.language; 15 | } 16 | 17 | async function getPlatformInfo() 18 | { 19 | if(navigator.platform && navigator.platform.startsWith("Win")) 20 | return {os: 'win'}; 21 | let platformInfoPromise = browser.runtime.getPlatformInfo(); 22 | return platformInfoPromise.then((platformInfo) => { 23 | return platformInfo; 24 | }).catch((error) => { 25 | return {os: 'android'}; 26 | }) 27 | } 28 | 29 | async function isMobileDevice() { 30 | let os = (await getPlatformInfo()).os; 31 | return os === 'android'; 32 | } 33 | 34 | function getVersion(){ 35 | return browser.runtime.getManifest().version; 36 | } 37 | 38 | return { 39 | getUserAgent, 40 | getAllInstalledPlugins, 41 | getBrowserLanguage, 42 | getPlatformInfo, 43 | getVersion, 44 | isMobileDevice 45 | }; 46 | }()) 47 | 48 | export {browserUtils} -------------------------------------------------------------------------------- /js/configs/apiCall.json: -------------------------------------------------------------------------------- 1 | { 2 | "interval": 3600000, 3 | "delay": 1000 4 | } -------------------------------------------------------------------------------- /js/configs/community.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiBaseURL": "https://www.streamr.com/api/v1/communities", 3 | "datacoinAddress": "0x0cf0ee63788a0849fe5297f3407f701e122cc023", 4 | "communityAddress": "0x7482ba34eafbf5c2f62f9c2e7a669ccbd9537fc3", 5 | "tokenExpiration": 540000 6 | } 7 | -------------------------------------------------------------------------------- /js/configs/memberManager.json: -------------------------------------------------------------------------------- 1 | { 2 | "minimumMessageNumber": 0, 3 | "sendTimeWindow": 300000, 4 | "strategy": "immediateJoinStrategy", 5 | "tryInterval": 6000, 6 | "maxInterval": 3600000, 7 | "failuresThreshold": 2, 8 | "backoffRate": 2 9 | } -------------------------------------------------------------------------------- /js/configs/stream.json: -------------------------------------------------------------------------------- 1 | { 2 | "Beauty": { 3 | "streamId": "K6iTnH2NTgOvQPc1ZkJ1TQ" 4 | }, 5 | "Fashion": { 6 | "streamId": "3ZXD2TvaTi-R_2PRQRjm3A" 7 | }, 8 | "General": { 9 | "streamId": "KT1OgUisRZq_DOEoKz3Q9Q" 10 | }, 11 | "Music": { 12 | "streamId": "EHXviMe7QH-pcVucEB3Xug" 13 | }, 14 | "News": { 15 | "streamId": "-EczD8WYReKxdfvBGgs8Yg" 16 | }, 17 | "Search" :{ 18 | "streamId": "kyqokh62Qn-a2_4jiFrbUg" 19 | }, 20 | "Shopping": { 21 | "streamId": "94ylzZvOTdqf_kHFkLT2Aw" 22 | }, 23 | "Social": { 24 | "streamId": "hxujfUckSwSea4Ta_PQSPQ" 25 | }, 26 | "Travel": { 27 | "streamId": "E9ccaB2LRDmDp96LdiSv4Q" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /js/configs/stream.sample.json: -------------------------------------------------------------------------------- 1 | { 2 | "Amazon":{ 3 | "streamId": "aaaaaaaaaaaaaaaaaaaaaa", 4 | "apiKey": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 5 | }, 6 | "Facebook":{ 7 | "streamId": "aaaaaaaaaaaaaaaaaaaaaa", 8 | "apiKey": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 9 | }, 10 | "Search":{ 11 | "streamId": "aaaaaaaaaaaaaaaaaaaaaa", 12 | "apiKey": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 13 | }, 14 | "Surfing":{ 15 | "streamId": "aaaaaaaaaaaaaaaaaaaaaa", 16 | "apiKey": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 17 | }, 18 | "Twitter":{ 19 | "streamId": "aaaaaaaaaaaaaaaaaaaaaa", 20 | "apiKey": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 21 | }, 22 | "Youtube":{ 23 | "streamId": "aaaaaaaaaaaaaaaaaaaaaa", 24 | "apiKey": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /js/configs/swashAPI.json: -------------------------------------------------------------------------------- 1 | { 2 | "endpoint": "https://api.swashapp.io/v1", 3 | "APIs": { 4 | "userJoin": "/user/join", 5 | "userReferralReward": "/user/referral/reward", 6 | "userReferralClaim": "/user/referral/claim", 7 | "userBalanceWithdraw": "/user/balance/withdraw", 8 | "balanceWithdraw": "/balance/withdraw", 9 | "referralActive": "/referral/active", 10 | "ipLookup": "/tools/ip/lookup", 11 | "charityList": "/charity/list" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /js/content_scripts/context_script.js: -------------------------------------------------------------------------------- 1 | var contextScript = (function () { 2 | var cta_callbacks = []; 3 | 4 | 5 | function send_msg(msg){ 6 | browser.runtime.sendMessage(msg); 7 | } 8 | 9 | 10 | function getScreenResolution() { 11 | return {width:window.screen.width, height: window.screen.height}; 12 | } 13 | 14 | function getScrolls() { 15 | return {scrollMaxX:window.scrollMaxX, scrollMaxY:window.scrollMaxY, fullscreen:window.fullScreen} 16 | } 17 | 18 | function getWindowSize() { 19 | return {height: window.innerHeight, width:window.innerWidth}; 20 | } 21 | 22 | async function getCache() { 23 | let cacheStorage = {}; 24 | let cacheNames = await window.caches.keys(); 25 | cacheNames.forEach(async function(cacheName) { 26 | cacheStorage[cacheNames] = await window.caches.open(cacheName).keys(); 27 | }); 28 | return cacheStorage; 29 | } 30 | 31 | 32 | async function context_attr_connect(p) { 33 | let message = {} 34 | for(let cta of cta_callbacks){ 35 | message[cta.name] = await cta.callback(); 36 | } 37 | p.postMessage(message); 38 | } 39 | function handleResponse(message) { 40 | message.context.forEach(obj=>{ 41 | switch(obj.name){ 42 | case "resolution": 43 | cta_callbacks.push({name: "resolution", callback: getScreenResolution}) 44 | break; 45 | case "scroll": 46 | cta_callbacks.push({name: "scroll", callback: getScrolls}) 47 | break; 48 | case "windowSize": 49 | cta_callbacks.push({name: "windowSize", callback: getWindowSize}) 50 | break; 51 | case "cache": 52 | cta_callbacks.push({name: "cache", callback: getCache}) 53 | break; 54 | } 55 | }); 56 | 57 | if(cta_callbacks.length > 0) { 58 | browser.runtime.onConnect.addListener(context_attr_connect); 59 | } 60 | } 61 | 62 | function handleError(error) { 63 | console.error(`Error: ${error}`); 64 | } 65 | 66 | return { 67 | handleResponse: handleResponse, 68 | handleError: handleError 69 | } 70 | }()); 71 | 72 | if(typeof window.surfStreamrContextMessage === 'undefined') { 73 | window.surfStreamrContextMessage = { 74 | obj: "context", 75 | func: "injectAttrCollectors", 76 | params: [window.location.href] 77 | } 78 | 79 | browser.runtime.sendMessage(window.surfStreamrContextMessage).then(contextScript.handleResponse, contextScript.handleError); 80 | } 81 | 82 | -------------------------------------------------------------------------------- /js/content_scripts/task_script.js: -------------------------------------------------------------------------------- 1 | var taskScript = (function () { 2 | var callbacks = {}; 3 | var startedTasks = {}; 4 | 5 | function uuid() { 6 | function randomDigit() { 7 | if (crypto && crypto.getRandomValues) { 8 | var rands = new Uint8Array(1); 9 | crypto.getRandomValues(rands); 10 | return (rands[0] % 16).toString(16); 11 | } else { 12 | return ((Math.random() * 16) | 0).toString(16); 13 | } 14 | } 15 | var crypto = window.crypto || window.msCrypto; 16 | return 'xxxxxxxx-xxxx-4xxx-8xxx-xxxxxxxxxxxx'.replace(/x/g, randomDigit); 17 | } 18 | 19 | 20 | function isIterable(obj) { 21 | // checks for null and undefined 22 | if (obj == null) { 23 | return false; 24 | } 25 | return typeof obj[Symbol.iterator] === 'function'; 26 | } 27 | 28 | function isEmpty(obj) { 29 | 30 | // null and undefined are "empty" 31 | if (obj == null) return true; 32 | 33 | // Assume if it has a length property with a non-zero value 34 | // that that property is correct. 35 | if (obj.length > 0) return false; 36 | if (obj.length === 0) return true; 37 | 38 | // If it isn't an object at this point 39 | // it is empty, but it can't be anything *but* empty 40 | // Is it empty? Depends on your application. 41 | if (typeof obj !== "object") return true; 42 | 43 | // Otherwise, does it have any properties of its own? 44 | // Note that this doesn't handle 45 | // toString and valueOf enumeration bugs in IE < 9 46 | for (var key in obj) { 47 | if (hasOwnProperty.call(obj, key)) return false; 48 | } 49 | 50 | return true; 51 | } 52 | 53 | 54 | function send_msg(msg){ 55 | browser.runtime.sendMessage(msg); 56 | } 57 | 58 | function taskSuccess(task, data) { 59 | let resp = true; 60 | for(cn of task.conditions) { 61 | switch(cn.operator) { 62 | case '>': 63 | resp = resp&&(data[cn.property] > cn.value) 64 | break; 65 | case '>=': 66 | resp = resp&&(data[cn.property] >= cn.value) 67 | break; 68 | case '<': 69 | resp = resp&&(data[cn.property] < cn.value) 70 | break; 71 | case '<=': 72 | resp = resp&&(data[cn.property] <= cn.value) 73 | break; 74 | case '=': 75 | resp = resp&&(data[cn.property] == cn.value) 76 | break; 77 | case '!=': 78 | resp = resp&&(data[cn.property] != cn.value) 79 | break; 80 | case 'regEx': 81 | resp = resp&&(data[cn.property].match(cn.value)) 82 | break; 83 | case 'contains': 84 | resp = resp&&(data[cn.property].indexOf(cn.value) >= 0) 85 | break; 86 | } 87 | } 88 | return resp; 89 | } 90 | 91 | function start_callback(task, moduleName, event) { 92 | let message = { 93 | obj: "task", 94 | func: "manageTask", 95 | params: [{ 96 | moduleName: moduleName, 97 | name: task.name, 98 | taskId: uuid(), 99 | created: false 100 | }] 101 | } 102 | startedTasks[task.name] = message; 103 | send_msg(message); 104 | } 105 | 106 | 107 | function end_callback(task, moduleName, event){ 108 | if(!startedTasks[task.name]) 109 | return; 110 | let data = {}; 111 | task.conditions.forEach(x=>{ 112 | var obj = null; 113 | switch(x.selector) { 114 | case "window": 115 | obj = window; 116 | break; 117 | case "document": 118 | obj = document; 119 | break; 120 | case "": 121 | obj = event.currentTarget; 122 | break; 123 | case ".": 124 | obj = event; 125 | break; 126 | default: 127 | obj = document.querySelector(x.selector); 128 | break; 129 | } 130 | if(obj != null){ 131 | data[x.property] = obj[x.property]; 132 | } 133 | }); 134 | 135 | 136 | let message = { 137 | obj: "task", 138 | func: "manageTask", 139 | params: [{ 140 | url: window.location.href, 141 | moduleName: moduleName, 142 | name: task.name, 143 | success: taskSuccess(task, data), 144 | created: true 145 | }] 146 | } 147 | delete startedTasks[task.name]; 148 | send_msg(message); 149 | 150 | } 151 | 152 | function registerEvent(event, callback) { 153 | if(event.selector == "window"){ 154 | // window 155 | window.addEventListener(event.event_name, callback); 156 | }else 157 | if(event.selector == "document"){ 158 | // document 159 | document.addEventListener(event.event_name, callback); 160 | } 161 | else{ 162 | let doms = document.querySelectorAll(event.selector) 163 | if(doms) { 164 | if(isIterable(doms)) { 165 | doms.forEach(dom=> { 166 | dom.addEventListener(event.event_name, callback); 167 | }) 168 | } 169 | else { 170 | doms.addEventListener(event.event_name, callback); 171 | } 172 | } 173 | } 174 | } 175 | 176 | function handleResponse(message) { 177 | message.tasks.forEach(obj=>{ 178 | let startEvent = obj.startEvent; 179 | let startCallback = function(x){start_callback(obj, message.moduleName, x)}; 180 | callbacks[message.moduleName + "_" + startEvent.event_name] = startCallback; 181 | registerEvent(startEvent, startCallback); 182 | 183 | let endEvent = obj.endEvent; 184 | let endCallback = function(x){end_callback(obj, message.moduleName, x)}; 185 | callbacks[message.moduleName + "_" + endEvent.event_name] = endCallback; 186 | registerEvent(endEvent, endCallback); 187 | 188 | }); 189 | window.addEventListener("load", (x) => {}); 190 | startedTasks = message.startedTasks?message.startedTasks:{} 191 | } 192 | 193 | function handleError(error) { 194 | console.error(`Error: ${error}`); 195 | } 196 | 197 | return { 198 | handleResponse: handleResponse, 199 | handleError: handleError 200 | } 201 | }()); 202 | 203 | 204 | 205 | 206 | 207 | if(typeof window.surfStreamrTaskMessage === 'undefined') { 208 | window.surfStreamrTaskMessage = { 209 | obj: "task", 210 | func: "injectTasks", 211 | params: [window.location.href] 212 | } 213 | 214 | browser.runtime.sendMessage(surfStreamrTaskMessage).then(taskScript.handleResponse, taskScript.handleError); 215 | } 216 | 217 | -------------------------------------------------------------------------------- /js/dataHandler.js: -------------------------------------------------------------------------------- 1 | import {filterUtils} from './filterUtils.js'; 2 | import {privacyUtils} from './privacyUtils.js'; 3 | import {storageHelper} from './storageHelper.js'; 4 | import {databaseHelper} from './databaseHelper.js'; 5 | import {utils} from './utils.js'; 6 | import {stream} from './stream.js'; 7 | import {configManager} from './configManager.js'; 8 | import {browserUtils} from './browserUtils.js' 9 | import {swashApiHelper} from './swashApiHelper.js' 10 | 11 | 12 | let dataHandler = (function() { 13 | 'use strict'; 14 | let streams = {} 15 | let streamConfig; 16 | 17 | 18 | function init() { 19 | streamConfig = configManager.getConfig('stream') 20 | } 21 | 22 | function cancelSending(msgId) { 23 | databaseHelper.removeMessage(msgId); 24 | //clearTimeout(msgId); 25 | //storageHelper.removeMessage(msgId); 26 | } 27 | 28 | async function sendDelayedMessages() { 29 | let confs = await storageHelper.retrieveConfigs(); 30 | let time = Number((new Date()).getTime()) - confs.delay*60000; 31 | let rows = await databaseHelper.getReadyMessages(time); 32 | for(let row of rows) { 33 | let message = row.message; 34 | delete message.origin; 35 | try{ 36 | streams[message.header.category].produceNewEvent(message); 37 | } 38 | catch (err) { 39 | `failed to produce new event because of: ${err.message}` 40 | } 41 | } 42 | await databaseHelper.removeReadyMessages(time); 43 | } 44 | 45 | async function sendData(message, delay) { 46 | if(delay) { 47 | await databaseHelper.insertMessage(message); 48 | } 49 | else { 50 | delete message.origin; 51 | streams[message.header.category].produceNewEvent(message); 52 | } 53 | } 54 | 55 | 56 | async function prepareAndSend(message, module, delay, tabId) { 57 | if(!streams[message.header.category]) 58 | streams[message.header.category] = stream(streamConfig[module.category].streamId); 59 | if(module.context){ 60 | let bct_attrs = module.context.filter(function(ele,val){return (ele.type==="browser" && ele.is_enabled)}); 61 | if(bct_attrs.length > 0) { 62 | for(let ct of bct_attrs){ 63 | switch(ct.name) { 64 | case "agent": 65 | message.header.agent = await browserUtils.getUserAgent(); 66 | break; 67 | case "installedPlugins": 68 | message.header.installedPlugins = await browserUtils.getAllInstalledPlugins(); 69 | break; 70 | case "platform": 71 | message.header.platform = await browserUtils.getPlatformInfo(); 72 | break; 73 | case "language": 74 | message.header.language = browserUtils.getBrowserLanguage(); 75 | break; 76 | } 77 | } 78 | } 79 | 80 | 81 | let cct_attrs = module.context.filter(function(ele,val){return (ele.type==="content" && ele.is_enabled) }); 82 | 83 | if(cct_attrs.length > 0 && tabId) { 84 | var connectPort = browser.tabs.connect( 85 | tabId, 86 | {name: "content-attributes"} 87 | ); 88 | connectPort.onMessage.addListener(async function(attrs) { 89 | for(let attrName of Object.keys(attrs)) { 90 | message.header[attrName] = attrs[attrName]; 91 | } 92 | await sendData(message, delay); 93 | 94 | }); 95 | return true; 96 | } 97 | 98 | } 99 | await sendData(message, delay); 100 | return false; 101 | } 102 | 103 | async function handle(message, tabId) { 104 | message.header.id = utils.uuid(); 105 | if(!message.origin) 106 | message.origin = "undetermined"; 107 | let db = await storageHelper.retrieveAll(); 108 | //Return if Swash is disabled or the origin is excluded or module/collector is disabled 109 | let filters = db.filters; 110 | let modules = db.modules; 111 | let collector = modules[message.header.module][message.header.function].items.find(element => {return(element.name === message.header.collector)}) 112 | if(!db.configs.is_enabled 113 | || filterUtils.filter(message.origin, filters) 114 | || !modules[message.header.module].is_enabled 115 | || !collector.is_enabled) 116 | return; 117 | let configs = db.configs; 118 | let profile = db.profile; 119 | let privacyData = db.privacyData; 120 | let delay = configs.delay; 121 | 122 | message.header.category = modules[message.header.module].category; 123 | message.header.privacyLevel = modules[message.header.module].privacyLevel; 124 | message.header.anonymityLevel = modules[message.header.module].anonymityLevel; 125 | message.header.version = browserUtils.getVersion(); 126 | 127 | message.identity = {}; 128 | message.identity.uid = privacyUtils.anonymiseIdentity(configs.Id, message, modules[message.header.module]); 129 | message.identity.country = profile.country || (await swashApiHelper.getUserCountry()); 130 | message.identity.city = profile.city || ''; 131 | message.identity.gender = profile.gender; 132 | message.identity.age = profile.age; 133 | message.identity.income = profile.income; 134 | message.identity.agent = await browserUtils.getUserAgent(); 135 | message.identity.platform = await browserUtils.getPlatformInfo(); 136 | message.identity.language = browserUtils.getBrowserLanguage(); 137 | 138 | 139 | enforcePolicy(message, privacyData); 140 | prepareAndSend(message, modules[message.header.module], delay, tabId) 141 | } 142 | function enforcePolicy(message, privacyData) { 143 | let data = message.data.out; 144 | let schems = message.data.schems; 145 | var ptr = JsonPointer; 146 | for(let d of schems) { 147 | let jpointers = JSONPath.JSONPath({path: d.jpath, resultType: "pointer" ,json: message.data.out}); 148 | if(jpointers) 149 | { 150 | for (let jp of jpointers) { 151 | var val = ptr.get(message.data.out, jp); 152 | val = privacyUtils.anonymiseObject(val, d.type, message, privacyData) 153 | ptr.set(data, jp, val, true); 154 | } 155 | } 156 | } 157 | message.data = data; 158 | return message; 159 | } 160 | 161 | return { 162 | init, 163 | handle, 164 | cancelSending, 165 | sendDelayedMessages, 166 | enforcePolicy 167 | }; 168 | }()); 169 | export {dataHandler}; 170 | -------------------------------------------------------------------------------- /js/databaseHelper.js: -------------------------------------------------------------------------------- 1 | var databaseHelper = (function() { 2 | 'use strict'; 3 | 4 | var dbName; 5 | var connection; 6 | async function init() { 7 | if(!connection) { 8 | dbName = 'SwashDBV3'; 9 | connection = new JsStore.Connection(); 10 | await initJsStore(); 11 | } 12 | } 13 | function getDbSchema() { 14 | var tblMessage = { 15 | name: 'messages', 16 | columns: { 17 | id: { 18 | primaryKey: true, 19 | autoIncrement: true 20 | }, 21 | createTime: { 22 | notNull: true, 23 | dataType: JsStore.DATA_TYPE.Number 24 | }, 25 | message: { 26 | notNull: true, 27 | dataType: JsStore.DATA_TYPE.Object 28 | } 29 | } 30 | }; 31 | 32 | var tblStats = { 33 | name: 'stats', 34 | columns: { 35 | moduleName: { 36 | primaryKey: true 37 | }, 38 | messageCount: { 39 | notNull: true, 40 | dataType: JsStore.DATA_TYPE.Number 41 | }, 42 | lastSent: { 43 | notNull: true, 44 | dataType: JsStore.DATA_TYPE.Number 45 | } 46 | } 47 | }; 48 | 49 | var db = { 50 | name: dbName, 51 | tables: [tblMessage, tblStats] 52 | } 53 | return db; 54 | } 55 | 56 | async function initJsStore() { 57 | var isDbCreated = await connection.initDb(getDbSchema()); 58 | if (isDbCreated) { 59 | console.log('Message database created'); 60 | } 61 | else { 62 | console.log('Message database opened'); 63 | } 64 | } 65 | 66 | function updateMessageCount(moduleName) { 67 | let currentTime = Number((new Date()).getTime()); 68 | return connection.update({ 69 | in: 'stats', 70 | set: { 71 | 'messageCount': { 72 | '+': 1 73 | }, 74 | 'lastSent': currentTime 75 | }, 76 | where: { 77 | moduleName: moduleName, 78 | } 79 | 80 | }).then(function(rowsUpdated) { 81 | if(rowsUpdated === 0) { 82 | let row = { 83 | moduleName: moduleName, 84 | lastSent: currentTime, 85 | messageCount: 1, 86 | } 87 | //since Id is autoincrement column, so the row will be automatically generated. 88 | connection.insert({ 89 | into: 'stats', 90 | values: [row] 91 | }).then(function(rowsInserted) { 92 | }).catch(function(err) { 93 | console.error(err); 94 | }); 95 | } 96 | }).catch(function(err) { 97 | console.error(err); 98 | }); 99 | } 100 | 101 | async function getMessageCount(moduleName) { 102 | let rows = await connection.select({ 103 | from: 'stats', 104 | where: { 105 | moduleName: moduleName 106 | } 107 | }) 108 | return (rows && rows[0] && rows[0]['messageCount'])?rows[0]['messageCount']:0 109 | } 110 | 111 | async function getTotalMessageCount() { 112 | let rows = await connection.select({ 113 | from: 'stats', 114 | aggregate: { 115 | sum: 'messageCount' 116 | } 117 | }) 118 | return (rows && rows[0] && rows[0]['sum(messageCount)'])?rows[0]['sum(messageCount)']:0 119 | } 120 | 121 | async function getLastSentDate() { 122 | let rows = await connection.select({ 123 | from: 'stats', 124 | aggregate: { 125 | max: 'lastSent' 126 | } 127 | }) 128 | return (rows && rows[0] && rows[0]['max(lastSent)'])?rows[0]['max(lastSent)']:0 129 | } 130 | 131 | function insertMessage(message) { 132 | let currentTime = Number((new Date()).getTime()); 133 | var row = { 134 | createTime: currentTime, 135 | message: message 136 | } 137 | //since Id is autoincrement column, so the row will be automatically generated. 138 | return connection.insert({ 139 | into: 'messages', 140 | values: [row] 141 | }).then(function(rowsInserted) { 142 | }).catch(function(err) { 143 | console.error(err); 144 | }); 145 | 146 | } 147 | 148 | async function getAllMessages() { 149 | let messages = await connection.select({ 150 | from: 'messages', 151 | }) 152 | return messages 153 | } 154 | 155 | async function getReadyMessages(time) { 156 | let rows = await connection.select({ 157 | from: 'messages', 158 | where: { 159 | createTime: { 160 | '<=': time 161 | } 162 | } 163 | }) 164 | return rows 165 | } 166 | 167 | async function removeReadyMessages(time) { 168 | return connection.remove({ 169 | from: 'messages', 170 | where: { 171 | createTime: { 172 | '<=': time 173 | } 174 | } 175 | }).then(function(rowsDeleted) { 176 | }).catch(function(err) { 177 | console.error(err); 178 | }); 179 | } 180 | 181 | function removeMessage(id) { 182 | return connection.remove({ 183 | from: 'messages', 184 | where: { 185 | id: id 186 | } 187 | }).then(function(rowsDeleted) { 188 | }).catch(function(err) { 189 | console.error(err); 190 | }); 191 | } 192 | 193 | return { 194 | updateMessageCount, 195 | getMessageCount, 196 | getTotalMessageCount, 197 | getLastSentDate, 198 | init, 199 | insertMessage, 200 | getAllMessages, 201 | getReadyMessages, 202 | removeReadyMessages, 203 | removeMessage, 204 | }; 205 | }()); 206 | export {databaseHelper}; -------------------------------------------------------------------------------- /js/filterUtils.js: -------------------------------------------------------------------------------- 1 | var filterUtils = (function() { 2 | 'use strict'; 3 | function regexFilter(input, regex) { 4 | if(input.match(regex)) 5 | return true; 6 | return false; 7 | } 8 | 9 | function matchFilter(input, match) { 10 | if(input === match) 11 | return true; 12 | return false; 13 | } 14 | 15 | function wildcardFilter(input, wildcard) { 16 | let regex = new RegExp('^' + wildcard.split(/\*+/).map(regExpEscape).join('.*') + '$'); 17 | if(input.match(regex)) 18 | return true; 19 | return false; 20 | } 21 | 22 | function regExpEscape (s) { 23 | return s.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&'); 24 | } 25 | 26 | function filter(input, filters) { 27 | let ret = false; 28 | for (let f of filters) { 29 | switch(f.type) { 30 | case "regex": 31 | ret = regexFilter(input, f.value); 32 | break; 33 | case "wildcard": 34 | ret = wildcardFilter(input, f.value); 35 | break; 36 | case "exact": 37 | ret = matchFilter(input, f.value); 38 | break; 39 | } 40 | if (ret) 41 | return ret; 42 | } 43 | return ret; 44 | } 45 | 46 | return { 47 | filter: filter 48 | }; 49 | 50 | }()); 51 | export {filterUtils}; -------------------------------------------------------------------------------- /js/functions.js: -------------------------------------------------------------------------------- 1 | import {browsing} from './functions/browsing.js'; 2 | import {content} from './functions/content.js'; 3 | import {apiCall} from './functions/apiCall.js'; 4 | import {context} from './functions/context.js'; 5 | import {task} from './functions/task.js'; 6 | import {transfer} from './functions/transfer.js'; 7 | 8 | var functions = [ 9 | browsing, 10 | content, 11 | apiCall, 12 | context, 13 | task, 14 | //transfer 15 | ] 16 | export {functions}; 17 | -------------------------------------------------------------------------------- /js/functions/content.js: -------------------------------------------------------------------------------- 1 | import {storageHelper} from '../storageHelper.js'; 2 | import {utils} from '../utils.js'; 3 | import {dataHandler} from '../dataHandler.js'; 4 | import {browserUtils} from '../browserUtils.js' 5 | 6 | 7 | var content = (function() { 8 | 'use strict'; 9 | 10 | var cfilter = {urls: [], properties: ["status"]}; 11 | 12 | async function initModule(module){ 13 | if(module.functions.includes("content")) { 14 | let info = await browserUtils.getPlatformInfo(); 15 | let platform = module.content.content_mapping[info.os]; 16 | if(!platform || typeof platform === "undefined") 17 | platform = 'desktop'; 18 | module.content.items = module.content[platform]; 19 | } 20 | } 21 | 22 | 23 | function unload(){ 24 | if(browser.tabs.onUpdated.hasListener(registerContentScripts)) 25 | browser.tabs.onUpdated.removeListener(registerContentScripts); 26 | } 27 | 28 | function load(){ 29 | storageHelper.retrieveModules().then(modules => { 30 | for (var module in modules) { 31 | loadModule(modules[module]); 32 | } 33 | }); 34 | } 35 | 36 | function unloadModule(module){ 37 | function arrayRemove(arr, value) { 38 | return arr.filter(function(ele){ 39 | return ele != value; 40 | }); 41 | } 42 | if(module.functions.includes("content")){ 43 | for(var item of module.content.content_matches) { 44 | cfilter.urls = arrayRemove(cfilter.urls,item); 45 | } 46 | if(browser.tabs.onUpdated.hasListener(registerContentScripts)) 47 | browser.tabs.onUpdated.removeListener(registerContentScripts); 48 | if(cfilter.urls.length > 0) 49 | browser.tabs.onUpdated.addListener(registerContentScripts); 50 | } 51 | } 52 | 53 | function loadModule(module){ 54 | if(module.is_enabled){ 55 | if(module.functions.includes("content")){ 56 | for(var item of module.content.content_matches) { 57 | cfilter.urls.push(item); 58 | } 59 | if(browser.tabs.onUpdated.hasListener(registerContentScripts)) 60 | browser.tabs.onUpdated.removeListener(registerContentScripts); 61 | if(cfilter.urls.length > 0) 62 | browser.tabs.onUpdated.addListener(registerContentScripts); 63 | } 64 | } 65 | } 66 | 67 | 68 | function registerContentScripts(tabId, changeInfo, tabInfo) { 69 | if(changeInfo.status == "loading") { 70 | let injectScript = false; 71 | for(let filter of cfilter.urls) { 72 | if(utils.wildcard(tabInfo.url, filter)) { 73 | injectScript = true; 74 | break; 75 | } 76 | } 77 | if(!injectScript) 78 | return; 79 | browser.tabs.executeScript(tabId, { 80 | file: "/lib/browser-polyfill.js", 81 | allFrames: false, 82 | runAt: "document_start" 83 | }).then(result => { 84 | browser.tabs.executeScript(tabId, { 85 | file: "/js/content_scripts/content_script.js", 86 | allFrames: false, 87 | runAt: "document_start" 88 | }) 89 | }) 90 | } 91 | } 92 | 93 | async function injectCollectors(url) { 94 | var modules = await storageHelper.retrieveModules(); 95 | let messages = []; 96 | for (var module in modules) { 97 | if(modules[module].functions.includes("content")){ 98 | if(modules[module].is_enabled) 99 | for(var item of modules[module].content.content_matches) { 100 | if(utils.wildcard(url, item)) { 101 | let content = modules[module].content.items.filter(function(cnt, index, arr){ 102 | return (cnt.is_enabled && utils.wildcard(url, cnt.url_match)); 103 | }); 104 | messages.push({moduleName: modules[module].name, content: content}); 105 | } 106 | } 107 | } 108 | } 109 | return messages; 110 | } 111 | return { 112 | initModule, 113 | load, 114 | unload, 115 | unloadModule, 116 | loadModule, 117 | injectCollectors 118 | }; 119 | }()); 120 | export {content}; -------------------------------------------------------------------------------- /js/functions/context.js: -------------------------------------------------------------------------------- 1 | import {storageHelper} from '../storageHelper.js'; 2 | import {utils} from '../utils.js'; 3 | import {dataHandler} from '../dataHandler.js'; 4 | 5 | 6 | var context = (function() { 7 | 'use strict'; 8 | 9 | var cfilter = {urls: [], properties: ["status"]}; 10 | 11 | function initModule(module){ 12 | 13 | } 14 | 15 | function unload(){ 16 | if(browser.tabs.onUpdated.hasListener(registerContextScripts)) 17 | browser.tabs.onUpdated.removeListener(registerContextScripts); 18 | } 19 | 20 | function load(){ 21 | storageHelper.retrieveModules().then(modules => { 22 | for (var module in modules) { 23 | loadModule(modules[module]); 24 | } 25 | }); 26 | } 27 | 28 | function unloadModule(module){ 29 | function arrayRemove(arr, value) { 30 | return arr.filter(function(ele){ 31 | return ele != value; 32 | }); 33 | } 34 | if(module.functions.includes("context")){ 35 | for(var item of module.contex.context_matches) { 36 | cfilter.urls = arrayRemove(cfilter.urls,item); 37 | } 38 | if(browser.tabs.onUpdated.hasListener(registerContextScripts)) 39 | browser.tabs.onUpdated.removeListener(registerContextScripts); 40 | if(cfilter.urls.length > 0) 41 | browser.tabs.onUpdated.addListener(registerContextScripts); 42 | } 43 | } 44 | 45 | function loadModule(module){ 46 | if(module.is_enabled){ 47 | if(module.functions.includes("context")){ 48 | for(var item of module.contex.context_matches) { 49 | cfilter.urls.push(item); 50 | } 51 | if(browser.tabs.onUpdated.hasListener(registerContextScripts)) 52 | browser.tabs.onUpdated.removeListener(registerContextScripts); 53 | if(cfilter.urls.length > 0) 54 | browser.tabs.onUpdated.addListener(registerContextScripts); 55 | } 56 | } 57 | } 58 | 59 | 60 | function registerContextScripts(tabId, changeInfo, tabInfo) { 61 | let injectScript = false; 62 | for(let filter of cfilter.urls) { 63 | if(utils.wildcard(tabInfo.url, filter)) { 64 | injectScript = true; 65 | break; 66 | } 67 | } 68 | if(changeInfo.status == "loading") 69 | browser.tabs.executeScript(tabId, { 70 | file: "/lib/browser-polyfill.js", 71 | allFrames: false, 72 | runAt: "document_start" 73 | }).then(result => { 74 | browser.tabs.executeScript(tabId, { 75 | file: "/js/content_scripts/context_script.js", 76 | allFrames: false, 77 | runAt: "document_start" 78 | }) 79 | }) 80 | } 81 | 82 | async function injectAttrCollectors(url) { 83 | var modules = await storageHelper.retrieveModules(); 84 | for (var module in modules) { 85 | if(modules[module].functions.includes("context")){ 86 | if(modules[module].is_enabled) 87 | for(var item of modules[module].contex.context_matches) { 88 | if(utils.wildcard(url, item)) { 89 | let context = modules[module].context.items.filter(function(cnt, index, arr){ 90 | return (cnt.is_enabled && cnt.type=="content"); 91 | }); 92 | return {moduleName: modules[module].name, context: context}; 93 | } 94 | } 95 | } 96 | } 97 | return; 98 | } 99 | return { 100 | initModule, 101 | load, 102 | unload, 103 | unloadModule, 104 | loadModule, 105 | injectAttrCollectors: injectAttrCollectors 106 | }; 107 | }()); 108 | export {context}; -------------------------------------------------------------------------------- /js/functions/task.js: -------------------------------------------------------------------------------- 1 | import {storageHelper} from '../storageHelper.js'; 2 | import {utils} from '../utils.js'; 3 | import {dataHandler} from '../dataHandler.js'; 4 | 5 | 6 | var task = (function() { 7 | 'use strict'; 8 | 9 | var cfilter = {urls: [], properties: ["status"]}; 10 | 11 | function initModule(module){ 12 | 13 | } 14 | 15 | function unload(){ 16 | if(browser.tabs.onUpdated.hasListener(registerTaskScripts)) 17 | browser.tabs.onUpdated.removeListener(registerTaskScripts); 18 | } 19 | 20 | function load(){ 21 | storageHelper.retrieveModules().then(modules => { 22 | for (var module in modules) { 23 | loadModule(modules[module]); 24 | } 25 | }); 26 | } 27 | 28 | function unloadModule(module){ 29 | function arrayRemove(arr, value) { 30 | return arr.filter(function(ele){ 31 | return ele != value; 32 | }); 33 | } 34 | if(module.functions.includes("task")){ 35 | for(var item of module.task.task_matches) { 36 | cfilter.urls = arrayRemove(cfilter.urls,item); 37 | } 38 | if(browser.tabs.onUpdated.hasListener(registerTaskScripts)) 39 | browser.tabs.onUpdated.removeListener(registerTaskScripts); 40 | if(cfilter.urls.length > 0) 41 | browser.tabs.onUpdated.addListener(registerTaskScripts); 42 | } 43 | } 44 | 45 | function loadModule(module){ 46 | if(module.is_enabled){ 47 | if(module.functions.includes("task")){ 48 | for(var item of module.task.task_matches) { 49 | cfilter.urls.push(item); 50 | } 51 | if(browser.tabs.onUpdated.hasListener(registerTaskScripts)) 52 | browser.tabs.onUpdated.removeListener(registerTaskScripts); 53 | if(cfilter.urls.length > 0) 54 | browser.tabs.onUpdated.addListener(registerTaskScripts); 55 | } 56 | } 57 | } 58 | 59 | 60 | function registerTaskScripts(tabId, changeInfo, tabInfo) { 61 | let injectScript = false; 62 | for(let filter of cfilter.urls) { 63 | if(utils.wildcard(tabInfo.url, filter)) { 64 | injectScript = true; 65 | break; 66 | } 67 | } 68 | 69 | if(changeInfo.status == "loading") 70 | browser.tabs.executeScript(tabId, { 71 | file: "/lib/browser-polyfill.js", 72 | allFrames: false, 73 | runAt: "document_start" 74 | }).then(result => { 75 | browser.tabs.executeScript(tabId, { 76 | file: "/js/content_scripts/task_script.js", 77 | allFrames: false, 78 | runAt: "document_end" 79 | }) 80 | }) 81 | } 82 | 83 | function createTask(info) { 84 | info.startTime = Date(); 85 | storageHelper.createTask(info); 86 | } 87 | 88 | async function sendTaskResult(info) { 89 | let task = await storageHelper.endTask(info); 90 | task.endTime = Date(); 91 | task.success = info.success; 92 | dataHandler.handle({ 93 | origin: info.url, 94 | header:{ 95 | function: "task", 96 | module: info.moduleName, 97 | collector: info.name 98 | }, 99 | data: { 100 | out: { 101 | task: task 102 | }, 103 | schems: [ 104 | {jpath: "$.task", type: "text"} 105 | ] 106 | } 107 | }); 108 | 109 | } 110 | 111 | function manageTask(info) { 112 | if(!info.created) { 113 | 114 | createTask(info); 115 | } 116 | else { 117 | sendTaskResult(info); 118 | } 119 | } 120 | 121 | async function injectTasks(url) { 122 | var modules = await storageHelper.retrieveModules(); 123 | for (var module in modules) { 124 | if(modules[module].functions.includes("task")){ 125 | if(modules[module].is_enabled) 126 | for(var item of modules[module].task.task_matches) { 127 | if(utils.wildcard(url, item)) { 128 | let tasks = modules[module].task.items.filter(function(cnt, index, arr){ 129 | return cnt.is_enabled; 130 | }); 131 | let startedTasks = await storageHelper.loadAllModuleTaskIds( modules[module].name); 132 | return {moduleName: modules[module].name, tasks: tasks, startedTasks: startedTasks}; 133 | } 134 | } 135 | } 136 | } 137 | return; 138 | } 139 | return { 140 | initModule, 141 | load, 142 | unload, 143 | unloadModule, 144 | loadModule, 145 | injectTasks: injectTasks, 146 | manageTask: manageTask 147 | }; 148 | }()); 149 | export {task}; -------------------------------------------------------------------------------- /js/functions/transfer.js: -------------------------------------------------------------------------------- 1 | var transfer = (function() { 2 | var pattern = "swash://*"; 3 | const regexp = "swash:\/\/(0x[a-fA-F0-9]{40})" 4 | 5 | 6 | function initModule(module){ 7 | } 8 | 9 | 10 | function showPageOnTab(url_to_show) { 11 | return browser.windows.getAll({ 12 | populate: true, 13 | windowTypes: ["normal"] 14 | }).then((windowInfoArray) => { 15 | browser.tabs.create({url: url_to_show, active: true}).then(x=>{ window.close(); }); 16 | }); 17 | } 18 | 19 | function openTransferDialog(wallet){ 20 | let url = browser.runtime.getURL("dashboard/index.html#/Transfer/" + wallet); 21 | return browser.windows.create({ 22 | url: url, 23 | type: "popup" 24 | }); 25 | } 26 | function listener(requestDetails){ 27 | let res = requestDetails.url.match(regexp); 28 | let url = browser.runtime.getURL("dashboard/index.html#/Transfer/"+ res[1]); 29 | showPageOnTab(url); 30 | } 31 | 32 | function load(){ 33 | if(!browser.webRequest.onBeforeRequest.hasListener(listener)){ 34 | browser.webRequest.onBeforeRequest.addListener(listener, {urls: [pattern]}, ["blocking"]); 35 | } 36 | 37 | if(browser.tabs.onUpdated.hasListener(registerContentScripts)) 38 | browser.tabs.onUpdated.removeListener(registerContentScripts); 39 | browser.tabs.onUpdated.addListener(registerContentScripts); 40 | } 41 | 42 | function unload(){ 43 | if(browser.tabs.onUpdated.hasListener(registerContentScripts)) 44 | browser.tabs.onUpdated.removeListener(registerContentScripts); 45 | 46 | 47 | if(browser.webRequest.onBeforeRequest.hasListener(listener)){ 48 | browser.webRequest.onBeforeRequest.removeListener(listener); 49 | } 50 | } 51 | 52 | function registerContentScripts(tabId, changeInfo, tabInfo) { 53 | if(changeInfo.status == "loading") { 54 | browser.tabs.executeScript(tabId, { 55 | file: "/lib/browser-polyfill.js", 56 | allFrames: false, 57 | runAt: "document_start" 58 | }).then(result => { 59 | browser.tabs.executeScript(tabId, { 60 | file: "/js/content_scripts/transfer_script.js", 61 | allFrames: false, 62 | runAt: "document_start" 63 | }) 64 | }).then(result => { 65 | browser.tabs.insertCSS(tabId, { 66 | file: "/css/transfer.css", 67 | allFrames: false, 68 | runAt: "document_start" 69 | }) 70 | }) 71 | } 72 | } 73 | 74 | return { 75 | load, 76 | unload, 77 | initModule, 78 | openTransferDialog 79 | }; 80 | }()); 81 | export {transfer}; 82 | -------------------------------------------------------------------------------- /js/internalFilters.js: -------------------------------------------------------------------------------- 1 | var internalFilters = [ 2 | { 3 | "value": "https://*.dropbox.com/*", 4 | "type": "wildcard", 5 | "internal": true 6 | }, 7 | { 8 | "value": "https://www.amazon.com/ap/signin*", 9 | "type": "wildcard", 10 | "internal": true 11 | }, 12 | { 13 | "value": "https://www.facebook.com/login*", 14 | "type": "wildcard", 15 | "internal": true 16 | }, 17 | { 18 | "value": "https://www.facebook.com/v3.2/dialog/oauth*", 19 | "type": "wildcard", 20 | "internal": true 21 | }, 22 | { 23 | "value": "https://login.yahoo.com/*", 24 | "type": "wildcard", 25 | "internal": true 26 | }, 27 | { 28 | "value": "https://accounts.google.com/*", 29 | "type": "wildcard", 30 | "internal": true 31 | }, 32 | { 33 | "value": "https://login.live.com/*", 34 | "type": "wildcard", 35 | "internal": true 36 | }, 37 | { 38 | "value": "https://login.aol.com/*", 39 | "type": "wildcard", 40 | "internal": true 41 | }, 42 | { 43 | "value": "https://twitter.com/login*", 44 | "type": "wildcard", 45 | "internal": true 46 | }, 47 | { 48 | "value": "https://twitter.com/account*", 49 | "type": "wildcard", 50 | "internal": true 51 | }, 52 | { 53 | "value": "https://drive.google.com/*", 54 | "type": "wildcard", 55 | "internal": true 56 | }, 57 | { 58 | "value": "https://docs.google.com/*", 59 | "type": "wildcard", 60 | "internal": true 61 | }, 62 | { 63 | "value": "^(?!http[s]?:).+", 64 | "type": "regex", 65 | "internal": true 66 | }, 67 | { 68 | "value": "(http|https):\/\/(localhost|([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}|(\\d{1,3}\\.){3}\\d{1,3}).*", 69 | "type": "regex", 70 | "internal": true 71 | } 72 | ] 73 | 74 | export {internalFilters}; -------------------------------------------------------------------------------- /js/manifest.js: -------------------------------------------------------------------------------- 1 | var ssConfig = (function() { 2 | 'use strict'; 3 | 4 | return { 5 | name: browser.runtime.getManifest().name, 6 | description: "Get paid for your data as you browse the web. Gain control and help create a better, more dignified internet.", 7 | path: "/", 8 | is_enabled: true, 9 | privacyLevel: 'auto', 10 | homepage_url: browser.runtime.getManifest().homepage_url, 11 | version: browser.runtime.getManifest().version, 12 | }; 13 | }()); 14 | export {ssConfig}; -------------------------------------------------------------------------------- /js/memberManager.js: -------------------------------------------------------------------------------- 1 | import {databaseHelper} from './databaseHelper.js' 2 | import {configManager} from './configManager.js' 3 | import {swashApiHelper} from "./swashApiHelper.js"; 4 | import {onboarding} from "./onboarding.js"; 5 | import {pageAction} from "./pageAction.js"; 6 | 7 | 8 | let memberManager = (function() { 9 | 10 | let joined = undefined; 11 | let failedCount = 0; 12 | let mgmtInterval = 0; 13 | let memberManagerConfig; 14 | let strategyInterval; 15 | 16 | function init() { 17 | memberManagerConfig = configManager.getConfig('memberManager'); 18 | if (memberManagerConfig) strategyInterval = memberManagerConfig.tryInterval; 19 | } 20 | 21 | function updateStatus(strategy) { 22 | console.log(`${strategy}: Trying to join...`); 23 | swashApiHelper.isJoinedSwash().then(status => { 24 | joined = status; 25 | if (status === false) { 26 | console.log(`${strategy}: user is not joined`); 27 | failedCount++; 28 | 29 | if (failedCount > memberManagerConfig.failuresThreshold) { 30 | clearJoinStrategy(); 31 | failedCount = 0; 32 | console.log(`need to join swash again`); 33 | onboarding.repeatOnboarding(['Join', 'Completed']).then(); 34 | } 35 | } else if (status === true) { 36 | console.log(`${strategy}: user is already joined`); 37 | clearJoinStrategy(); 38 | strategyInterval = memberManagerConfig.tryInterval; 39 | tryJoin(); 40 | browser.tabs.query({currentWindow: true, active: true}).then((tabs) => { 41 | let tab = tabs[0]; 42 | pageAction.loadIcons(tab.url) 43 | }, console.error); 44 | } else { 45 | console.log(`${strategy}: failed to get user join status`); 46 | if (strategyInterval < memberManagerConfig.maxInterval) { 47 | clearJoinStrategy(); 48 | strategyInterval *= memberManagerConfig.backoffRate; 49 | if (strategyInterval > memberManagerConfig.maxInterval) strategyInterval = memberManagerConfig.maxInterval; 50 | tryJoin(); 51 | } 52 | } 53 | }); 54 | } 55 | 56 | let strategies = (function() { 57 | async function fixedTimeWindowStrategy() { 58 | let messageCount = await databaseHelper.getTotalMessageCount(); 59 | let lastSentDate = await databaseHelper.getLastSentDate(); 60 | let currentTime = (new Date()).getTime(); 61 | if (!joined && messageCount >= memberManagerConfig.minimumMessageNumber && lastSentDate + memberManagerConfig.sendTimeWindow >= currentTime) { 62 | updateStatus('FixedTimeWindowStrategy'); 63 | } 64 | 65 | if (joined && lastSentDate + memberManagerConfig.sendTimeWindow < currentTime) { 66 | updateStatus('FixedTimeWindowStrategy'); 67 | } 68 | } 69 | 70 | async function dynamicTimeWindowStrategy() { 71 | let messageCount = await databaseHelper.getTotalMessageCount(); 72 | let lastSentDate = await databaseHelper.getLastSentDate(); 73 | let currentTime = (new Date()).getTime(); 74 | if (!joined && messageCount >= memberManagerConfig.minimumMessageNumber && (lastSentDate + messageCount * 60 * 1000) >= currentTime) { 75 | updateStatus('DynamicTimeWindowStrategy'); 76 | } 77 | 78 | if (joined && (lastSentDate + messageCount * 60 * 1000) < currentTime) { 79 | updateStatus('DynamicTimeWindowStrategy'); 80 | } 81 | } 82 | 83 | async function immediateJoinStrategy() { 84 | if (!joined) { 85 | updateStatus('ImmediateJoinStrategy'); 86 | } 87 | } 88 | 89 | return { 90 | fixedTimeWindowStrategy, 91 | dynamicTimeWindowStrategy, 92 | immediateJoinStrategy, 93 | } 94 | })() 95 | 96 | 97 | function tryJoin() { 98 | if(!mgmtInterval) mgmtInterval = setInterval(strategies[memberManagerConfig.strategy], strategyInterval); 99 | } 100 | 101 | function clearJoinStrategy() { 102 | clearInterval(mgmtInterval); 103 | mgmtInterval = 0; 104 | } 105 | 106 | function isJoined() { 107 | return joined; 108 | } 109 | 110 | return { 111 | init, 112 | tryJoin, 113 | isJoined 114 | }; 115 | }()) 116 | 117 | 118 | export {memberManager}; 119 | 120 | -------------------------------------------------------------------------------- /js/menu.js: -------------------------------------------------------------------------------- 1 | function filterIconStat(filtered) { 2 | let target = document.getElementById("add_filter"); 3 | if(filtered) { 4 | target.classList.add("active"); 5 | } 6 | else { 7 | target.classList.remove("active"); 8 | } 9 | } 10 | 11 | function showPageOnTab(url_to_show) { 12 | window.helper.isNeededOnBoarding().then((result) => { 13 | if (result) 14 | url_to_show = browser.runtime.getURL("dashboard/index.html#/OnBoarding"); 15 | return browser.windows.getAll({ 16 | populate: true, 17 | windowTypes: ["normal"] 18 | }).then((windowInfoArray) => { 19 | browser.tabs.create({url: url_to_show, active: true}).then(x=>{ window.close(); }); 20 | }); 21 | }); 22 | } 23 | 24 | 25 | function updateBalance(balance){ 26 | document.getElementById("balance").innerText = `${balance} DATA`; 27 | } 28 | 29 | function updateVersion(version){ 30 | document.getElementById("version").innerText = `V${version}`; 31 | } 32 | 33 | function purgeNumber(num) { 34 | if(num.indexOf('.') < 0) 35 | return num; 36 | return num.slice(0, num.indexOf('.') + 5) 37 | } 38 | 39 | document.getElementById("open_setting").addEventListener('click', function(eventObj) { 40 | let url = browser.runtime.getURL("dashboard/index.html"); 41 | showPageOnTab(url); 42 | }); 43 | 44 | document.getElementById("open_messages").addEventListener('click', function(eventObj) { 45 | let url = browser.runtime.getURL("dashboard/index.html#/Data"); 46 | showPageOnTab(url); 47 | }); 48 | 49 | 50 | document.getElementById("open_logs").addEventListener('click', function(eventObj) { 51 | let url = browser.runtime.getURL("dashboard/index.html#/Help"); 52 | showPageOnTab(url); 53 | }); 54 | 55 | document.getElementById("add_filter").addEventListener('click', function(eventObj) { 56 | window.helper.handleFilter().then(res => { 57 | filterIconStat(res); 58 | }); 59 | }); 60 | 61 | 62 | document.getElementById("streaming").addEventListener('click', function(eventObj) { 63 | let is_enabled = document.getElementById("streaming").checked; 64 | if(is_enabled) { 65 | window.helper.start(); 66 | } 67 | else { 68 | window.helper.stop(); 69 | } 70 | }); 71 | 72 | 73 | updateVersion(browser.runtime.getManifest().version); 74 | 75 | window.helper.load().then(db => { 76 | window.helper.isNeededOnBoarding().then((result) => { 77 | if (!result) { 78 | document.getElementById("streaming").checked = db.configs.is_enabled; 79 | 80 | window.helper.getTotalBalance().then(balance => { 81 | balance = (balance === '' || balance === 'undefined' || typeof (balance) === 'undefined') ? '0.00' : balance; 82 | updateBalance(purgeNumber(balance)); 83 | }) 84 | } 85 | }); 86 | }); 87 | 88 | window.helper.isCurrentDomainFiltered().then(filtered => { 89 | filterIconStat(filtered); 90 | }); 91 | -------------------------------------------------------------------------------- /js/modules/Beauty/bathandbodyworks/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "beauty_bathandbodyworks", 3 | "description": "This module Captures a user shopping bahaviour on bathandbodyworks", 4 | "functions": [ 5 | "content" 6 | ], 7 | "is_enabled": true, 8 | "privacyLevel": 1, 9 | "anonymityLevel": 1 10 | } -------------------------------------------------------------------------------- /js/modules/Beauty/faberlic/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "beauty_faberlic", 3 | "description": "This module Captures a user shopping behaviour on faberlic", 4 | "functions": [ 5 | "content" 6 | ], 7 | "is_enabled": true, 8 | "privacyLevel": 1, 9 | "anonymityLevel": 1 10 | } -------------------------------------------------------------------------------- /js/modules/Beauty/oriflame/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "beauty_oriflame", 3 | "description": "This module Captures a user shopping behaviour on oriflame", 4 | "functions": [ 5 | "content" 6 | ], 7 | "is_enabled": true, 8 | "privacyLevel": 1, 9 | "anonymityLevel": 1 10 | } -------------------------------------------------------------------------------- /js/modules/Beauty/sephora/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "beauty_sephora", 3 | "description": "This module Captures a user shopping bahaviour on sephora", 4 | "functions": [ 5 | "content" 6 | ], 7 | "is_enabled": true, 8 | "privacyLevel": 1, 9 | "anonymityLevel": 1 10 | } -------------------------------------------------------------------------------- /js/modules/Beauty/ulta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "beauty_ulta", 3 | "description": "This module Captures a user shopping bahaviour on ulta", 4 | "functions": [ 5 | "content" 6 | ], 7 | "is_enabled": true, 8 | "privacyLevel": 1, 9 | "anonymityLevel": 1 10 | } -------------------------------------------------------------------------------- /js/modules/General/surfing/browsing.json: -------------------------------------------------------------------------------- 1 | { 2 | "browsing_filter": { 3 | "urls": [ 4 | "" 5 | ] 6 | }, 7 | "browsing_extraInfoSpec": [], 8 | "items": [ 9 | { 10 | "name": "New Bookmark", 11 | "title": "Create Bookmark", 12 | "description": "This item collects all bookmarks that created by a user", 13 | "is_enabled": true, 14 | "hook": "bookmarks" 15 | } 16 | ] 17 | } -------------------------------------------------------------------------------- /js/modules/General/surfing/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "general_surfing", 3 | "description": "This module captures a user navigations for URL patterns that has been permitted by the user", 4 | "functions": [ 5 | "browsing", 6 | "content" 7 | ], 8 | "is_enabled": true, 9 | "privacyLevel": 3, 10 | "anonymityLevel": 2 11 | } -------------------------------------------------------------------------------- /js/modules/General/surfing/content.json: -------------------------------------------------------------------------------- 1 | { 2 | "content_matches": [ 3 | "*://*/*" 4 | ], 5 | "content_mapping": { 6 | "win": "desktop", 7 | "mac": "desktop", 8 | "android": "desktop", 9 | "cros": "desktop", 10 | "openbsd": "desktop", 11 | "ios": "desktop", 12 | "ipados": "desktop" 13 | }, 14 | "desktop": [ 15 | { 16 | "name": "pageInfo", 17 | "description": "This item collects information about the page being visited", 18 | "title": "Page Information", 19 | "url_match": "*://*/*", 20 | "type": "event", 21 | "is_enabled": true, 22 | "events": [ 23 | { 24 | "selector": "document", 25 | "event_name": "DOMContentLoaded" 26 | } 27 | ], 28 | "objects": [ 29 | { 30 | "selector": "title", 31 | "properties": [ 32 | { 33 | "property": "innerText", 34 | "name": "title", 35 | "type": "text" 36 | } 37 | ] 38 | }, 39 | { 40 | "selector": "document", 41 | "properties": [ 42 | { 43 | "selector": "meta[name=title]", 44 | "property": "content", 45 | "name": "meta-title", 46 | "type": "text" 47 | }, 48 | { 49 | "selector": "meta[name=description]", 50 | "property": "content", 51 | "name": "meta-description", 52 | "type": "text" 53 | }, 54 | { 55 | "property": "URL", 56 | "name": "location", 57 | "type": "url" 58 | }, 59 | { 60 | "property": "referrer", 61 | "name": "referrer", 62 | "type": "url" 63 | } 64 | ] 65 | } 66 | ] 67 | } 68 | ] 69 | } -------------------------------------------------------------------------------- /js/modules/Music/youtube/browsing.json: -------------------------------------------------------------------------------- 1 | { 2 | "browsing_filter": { 3 | "urls": [ 4 | "https://www.youtube.com/*" 5 | ] 6 | }, 7 | "items": [ 8 | { 9 | "name": "Page Action", 10 | "title": "Page actions", 11 | "is_enabled": true, 12 | "description": "This item collects all actions a user does in Youtube pages", 13 | "extraInfoSpec": [ 14 | "requestBody" 15 | ], 16 | "patterns": [ 17 | { 18 | "method": "POST", 19 | "url_pattern": "^https:\\/\\/www\\.youtube\\.com\\/service_ajax.*", 20 | "pattern_type": "regex", 21 | "param": [ 22 | { 23 | "type": "query", 24 | "key": "name", 25 | "name": "action" 26 | }, 27 | { 28 | "type": "form", 29 | "key": "sej", 30 | "name": "detail" 31 | } 32 | ], 33 | "schems": [ 34 | { 35 | "jpath": "$.action", 36 | "type": "text" 37 | }, 38 | { 39 | "jpath": "$.detail", 40 | "type": "text" 41 | } 42 | ] 43 | } 44 | ] 45 | }, 46 | { 47 | "name": "Search", 48 | "title": "Youtube Search", 49 | "is_enabled": true, 50 | "description": "This item collect all search queries that a user enters in Youtube search bar", 51 | "patterns": [ 52 | { 53 | "method": "GET", 54 | "url_pattern": "^https:\\/\\/www\\.youtube\\.com\\/results.*", 55 | "pattern_type": "regex", 56 | "param": [ 57 | { 58 | "type": "query", 59 | "key": "search_query", 60 | "name": "q" 61 | } 62 | ], 63 | "schems": [ 64 | { 65 | "jpath": "$.q", 66 | "type": "text" 67 | } 68 | ] 69 | } 70 | ] 71 | } 72 | ] 73 | } -------------------------------------------------------------------------------- /js/modules/Music/youtube/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "music_youtube", 3 | "description": "This module looks through all activities of a user on Youtube and captures those activities that the user has permitted", 4 | "functions": [ 5 | "content", 6 | "browsing" 7 | ], 8 | "is_enabled": true, 9 | "privacyLevel": 1, 10 | "anonymityLevel": 1 11 | } -------------------------------------------------------------------------------- /js/modules/Music/youtube/content.json: -------------------------------------------------------------------------------- 1 | { 2 | "content_matches": [ 3 | "*://*.youtube.com/*" 4 | ], 5 | "content_mapping": { 6 | "win": "desktop", 7 | "mac": "desktop", 8 | "android": "mobile", 9 | "cros": "desktop", 10 | "openbsd": "desktop", 11 | "ios": "mobile", 12 | "ipados": "desktop" 13 | }, 14 | "desktop": [ 15 | { 16 | "name": "Video Time Duration", 17 | "description": "This item collects the duration of a video watched by a user", 18 | "url_match": "*://*.youtube.com/*", 19 | "title": "video time duration", 20 | "type": "event", 21 | "readyAt": "windowChange", 22 | "observingTargetNode": "#primary .title", 23 | "observingConfig": { 24 | "attributes": false, 25 | "childList": true, 26 | "subtree": true 27 | }, 28 | "is_enabled": true, 29 | "events": [ 30 | { 31 | "selector": "window", 32 | "event_name": "beforeunload" 33 | }, 34 | { 35 | "selector": "a", 36 | "event_name": "click" 37 | } 38 | ], 39 | "objects": [ 40 | { 41 | "isRequired": true, 42 | "selector": "#primary .ytp-time-duration", 43 | "properties": [ 44 | { 45 | "property": "innerHTML", 46 | "name": "duration", 47 | "type": "text" 48 | } 49 | ] 50 | }, 51 | { 52 | "isRequired": true, 53 | "selector": "#primary .ytp-time-current", 54 | "properties": [ 55 | { 56 | "property": "innerHTML", 57 | "name": "current", 58 | "type": "text" 59 | } 60 | ] 61 | }, 62 | { 63 | "selector": "#primary .title", 64 | "properties": [ 65 | { 66 | "property": "innerText", 67 | "name": "title", 68 | "type": "text" 69 | } 70 | ] 71 | } 72 | ] 73 | } 74 | ], 75 | "mobile": [ 76 | { 77 | "name": "Video Time Duration", 78 | "description": "This item collects the duration of a video watched by a user", 79 | "url_match": "*://*.youtube.com/*", 80 | "title": "video time duration", 81 | "type": "event", 82 | "readyAt": "windowChange", 83 | "observingTargetNode": "#primary .title", 84 | "observingConfig": { 85 | "attributes": false, 86 | "childList": true, 87 | "subtree": true 88 | }, 89 | "is_enabled": true, 90 | "events": [ 91 | { 92 | "selector": "window", 93 | "event_name": "beforeunload" 94 | }, 95 | { 96 | "selector": "a", 97 | "event_name": "click" 98 | } 99 | ], 100 | "objects": [ 101 | { 102 | "isRequired": true, 103 | "selector": ".time-second", 104 | "properties": [ 105 | { 106 | "property": "innerHTML", 107 | "name": "duration", 108 | "type": "text" 109 | } 110 | ] 111 | }, 112 | { 113 | "isRequired": true, 114 | "selector": ".time-first", 115 | "properties": [ 116 | { 117 | "property": "innerHTML", 118 | "name": "current", 119 | "type": "text" 120 | } 121 | ] 122 | }, 123 | { 124 | "selector": ".slim-video-metadata-title", 125 | "properties": [ 126 | { 127 | "property": "innerText", 128 | "name": "title", 129 | "type": "text" 130 | } 131 | ] 132 | } 133 | ] 134 | } 135 | ] 136 | } -------------------------------------------------------------------------------- /js/modules/News/bbc/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "news_BBC", 3 | "description": "This module looks through all activities of a user on BBC media and captures those activities that the user has permitted", 4 | "functions": [ 5 | "content" 6 | ], 7 | "is_enabled": true, 8 | "privacyLevel": 1, 9 | "anonymityLevel": 1 10 | } -------------------------------------------------------------------------------- /js/modules/News/bbc/content.json: -------------------------------------------------------------------------------- 1 | { 2 | "content_matches": [ 3 | "*://*.bbc.com/*", 4 | "*://*.bbc.co.uk/*" 5 | ], 6 | 7 | "content_mapping": { 8 | "win": "desktop", 9 | "mac": "desktop", 10 | "android": "desktop", 11 | "cros": "desktop", 12 | "openbsd": "desktop", 13 | "ios": "desktop", 14 | "ipados": "desktop" 15 | }, 16 | 17 | "desktop": [ 18 | { 19 | "name": "bbcLink", 20 | "description": "This item collects news title and news url after click", 21 | "viewGroup": "PInfo", 22 | "title": "bbc News", 23 | "url_match": "*://*.bbc.com/*", 24 | "type": "event", 25 | "is_enabled": true, 26 | "events": [{ 27 | "selector": "a", 28 | "event_name": "click" 29 | }, 30 | { 31 | "selector": "a", 32 | "event_name": "contextmenu" 33 | } 34 | ], 35 | "objects": [{ 36 | "selector": "", 37 | "properties": [{ 38 | "property": "innerText", 39 | "name": "title", 40 | "type": "text" 41 | }, 42 | { 43 | "property": "href", 44 | "name": "link", 45 | "type": "url" 46 | } 47 | ] 48 | }] 49 | }, 50 | 51 | 52 | 53 | { 54 | "name": "bbcNewsdetail", 55 | "description": "This item collects category, title, author, date and time of news", 56 | "viewGroup": "PInfo", 57 | "title": "bbc details", 58 | "url_match": "*://*.bbc.com/news/*", 59 | "type": "event", 60 | "is_enabled": true, 61 | "events": [{ 62 | "selector": "window", 63 | "event_name": "DOMContentLoaded" 64 | }], 65 | 66 | "objects": [{ 67 | "selector": "document", 68 | "properties": [{ 69 | "selector": "h1", 70 | "property": "innerText", 71 | "name": "Title", 72 | "type": "text" 73 | }, 74 | { 75 | "selector": ".byline__name", 76 | "property": "innerText", 77 | "name": "Author", 78 | "type": "text" 79 | }, 80 | { 81 | "selector": "a.css-6v54e1-StyledLink.eis6szr1", 82 | "property": "innerText", 83 | "name": "category", 84 | "type": "text" 85 | }, { 86 | "selector": "time", 87 | "isRequired": true, 88 | "property": "innerText", 89 | "name": "time", 90 | "type": "text" 91 | } 92 | 93 | ] 94 | 95 | }] 96 | }, 97 | 98 | { 99 | "name": "bbcsportdetail", 100 | "description": "This item collects category, title, author, date and time of news", 101 | "viewGroup": "PInfo", 102 | "title": "bbc sportNews details", 103 | "url_match": "*://*.bbc.com/sport/^(?!.*(live))*", 104 | "type": "event", 105 | "is_enabled": true, 106 | "events": [{ 107 | "selector": "window", 108 | "event_name": "DOMContentLoaded" 109 | }], 110 | "objects": [{ 111 | "selector": "document", 112 | "properties": [{ 113 | "selector": "h1", 114 | "property": "innerText", 115 | "name": "Title", 116 | "type": "text" 117 | }, 118 | { 119 | "selector": ".qa-contributor-name.gel-long-primer", 120 | "property": "innerText", 121 | "name": "Author", 122 | "type": "text" 123 | }, 124 | { 125 | "category": "sport", 126 | "name": "category", 127 | "type": "text" 128 | }, 129 | { 130 | "selector": "time", 131 | "isRequired": true, 132 | "property": "innerText", 133 | "name": "Time", 134 | "type": "text" 135 | } 136 | ] 137 | 138 | }] 139 | 140 | } 141 | ] 142 | } -------------------------------------------------------------------------------- /js/modules/News/cnn/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "news_cnn", 3 | "description": "This module looks through all activities of a user on cnn media and captures those activities that the user has permitted", 4 | "functions": [ 5 | "content" 6 | ], 7 | "is_enabled": true, 8 | "privacyLevel": 1, 9 | "anonymityLevel": 1 10 | } -------------------------------------------------------------------------------- /js/modules/News/cnn/content.json: -------------------------------------------------------------------------------- 1 | { 2 | "content_matches": [ 3 | "*://*.cnn.com*" 4 | ], 5 | "content_mapping": { 6 | "win": "desktop", 7 | "mac": "desktop", 8 | "android": "desktop", 9 | "cros": "desktop", 10 | "openbsd": "desktop", 11 | "ios": "desktop", 12 | "ipados": "desktop" 13 | }, 14 | "desktop": [{ 15 | "name": "CNNLink", 16 | "description": "This item collects news title and news url after click", 17 | "viewGroup": "PInfo", 18 | "title": "CNN News", 19 | "url_match": "*://*.cnn.com*", 20 | "type": "event", 21 | "is_enabled": true, 22 | "events": [{ 23 | "selector": "a", 24 | "event_name": "click" 25 | }, 26 | { 27 | "selector": "a", 28 | "event_name": "contextmenu" 29 | } 30 | ], 31 | "objects": [{ 32 | "selector": "", 33 | "properties": [ 34 | { 35 | "property": "href", 36 | "name": "link", 37 | "type": "url" 38 | },{ 39 | "property": "innerText", 40 | "name": "title", 41 | "type": "text" 42 | } 43 | ] 44 | }] 45 | }, 46 | 47 | { 48 | "name": "cnnnewsdetail", 49 | "description": "This item collects category, title, author, date and time of news", 50 | "viewGroup": "PInfo", 51 | "title": "cnn News details", 52 | "url_match": "*://*.cnn.com/*", 53 | "type": "event", 54 | "is_enabled": true, 55 | "events": [{ 56 | "selector": "window", 57 | "event_name": "DOMContentLoaded" 58 | }], 59 | "objects": [{ 60 | "selector": "document", 61 | "properties": [{ 62 | "selector": "h1", 63 | "property": "innerText", 64 | "name": "Title", 65 | "type": "text" 66 | }, 67 | { 68 | "selector": "#header-nav-container a[data-test=section-link]", 69 | "property": "attributes['aria-label'].value", 70 | "name": "category", 71 | "type": "text" 72 | }, 73 | { 74 | "selector": ".metadata__byline", 75 | "property": "innerText", 76 | "name": "Author", 77 | "type": "text" 78 | }, 79 | { 80 | "selector": ".update-time", 81 | "isRequired": true, 82 | "property": "innerText", 83 | "name": "Time", 84 | "type": "text" 85 | } 86 | ] 87 | 88 | }] 89 | } 90 | ] 91 | } -------------------------------------------------------------------------------- /js/modules/News/dailymail/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "news_dailymail", 3 | "description": "This module looks through all activities of a user on dailymail media and captures those activities that the user has permitted", 4 | "functions": [ 5 | "content" 6 | ], 7 | "is_enabled": true, 8 | "privacyLevel": 1, 9 | "anonymityLevel": 1 10 | } -------------------------------------------------------------------------------- /js/modules/News/dailymail/content.json: -------------------------------------------------------------------------------- 1 | { 2 | "content_matches": [ 3 | "*://*.dailymail.co.uk/*" 4 | ], 5 | "content_mapping": { 6 | "win": "desktop", 7 | "mac": "desktop", 8 | "android": "desktop", 9 | "cros": "desktop", 10 | "openbsd": "desktop", 11 | "ios": "desktop", 12 | "ipados": "desktop" 13 | }, 14 | "desktop": [ 15 | { 16 | "name": "dailyMailLink", 17 | "description": "This item collects news title and news url after click", 18 | "viewGroup": "PInfo", 19 | "title": "dailyMail News", 20 | "url_match": "*://*.dailymail.co.uk/*", 21 | "type": "event", 22 | "is_enabled": true, 23 | "events": [{ 24 | "selector": "a", 25 | "event_name": "click" 26 | }, 27 | { 28 | "selector": "a", 29 | "event_name": "contextmenu" 30 | } 31 | ], 32 | "objects": [{ 33 | "selector": "", 34 | "properties": [{ 35 | "property": "innerText", 36 | "name": "title", 37 | "type": "text" 38 | }, 39 | { 40 | "property": "href", 41 | "name": "link", 42 | "type": "url" 43 | } 44 | ] 45 | }] 46 | }, 47 | { 48 | "name": "dailyMailNewsdetail", 49 | "description": "This item collects category, title, author, date and time of news", 50 | "viewGroup": "PInfo", 51 | "title": "dailyMail News details", 52 | "url_match": "*://*.dailymail.co.uk/*", 53 | "type": "event", 54 | "is_enabled": true, 55 | "events": [{ 56 | "selector": "window", 57 | "event_name": "DOMContentLoaded" 58 | }], 59 | "objects": [{ 60 | "selector": "document", 61 | "properties": [{ 62 | "selector": "h2", 63 | "property": "innerText", 64 | "name": "Title", 65 | "type": "text" 66 | }, 67 | { 68 | "selector": ".link-wocc.linkro-wocc.selected", 69 | "property": "innerText", 70 | "name": "category", 71 | "type": "text" 72 | }, 73 | { 74 | "selector": ".logo-row", 75 | "property": "innerText", 76 | "name": "category", 77 | "type": "text" 78 | }, 79 | { 80 | "selector": ".author-section.byline-plain", 81 | "property": "innerText", 82 | "name": "Author", 83 | "type": "text" 84 | }, 85 | { 86 | "selector": ".author", 87 | "property": "innerText", 88 | "name": "Author", 89 | "type": "text" 90 | }, 91 | { 92 | "selector": "time", 93 | "isRequired": true, 94 | "property": "innerText", 95 | "name": "Time", 96 | "type": "text" 97 | } 98 | ] 99 | 100 | }] 101 | } 102 | ] 103 | } -------------------------------------------------------------------------------- /js/modules/News/globo/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "news_globo", 3 | "description": "This module looks through all activities of a user on globo media and captures those activities that the user has permitted", 4 | "functions": [ 5 | "content" 6 | ], 7 | "is_enabled": true, 8 | "privacyLevel": 1, 9 | "anonymityLevel": 1 10 | } -------------------------------------------------------------------------------- /js/modules/News/msn/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "news_msn", 3 | "description": "This module looks through all activities of a user on msn media and captures those activities that the user has permitted", 4 | "functions": [ 5 | "content" 6 | ], 7 | "is_enabled": true, 8 | "privacyLevel": 1, 9 | "anonymityLevel": 1 10 | } -------------------------------------------------------------------------------- /js/modules/News/msn/content.json: -------------------------------------------------------------------------------- 1 | { 2 | "content_matches": [ 3 | "*://*.msn.com/*" 4 | ], 5 | "content_mapping": { 6 | "win": "desktop", 7 | "mac": "desktop", 8 | "android": "desktop", 9 | "cros": "desktop", 10 | "openbsd": "desktop", 11 | "ios": "desktop", 12 | "ipados": "desktop" 13 | }, 14 | "desktop": [ 15 | { 16 | "name": "msnLink", 17 | "description": "This item collects news title and news url after click", 18 | "viewGroup": "PInfo", 19 | "title": "msn News", 20 | "url_match": "*://*.msn.com/*", 21 | "type": "event", 22 | "is_enabled": true, 23 | "events": [{ 24 | "selector": "a", 25 | "event_name": "click" 26 | }, 27 | { 28 | "selector": "a", 29 | "event_name": "contextmenu" 30 | } 31 | ], 32 | "objects": [{ 33 | "selector": "", 34 | "properties": [{ 35 | "property": "innerText", 36 | "name": "title", 37 | "type": "text" 38 | }, 39 | { 40 | "property": "href", 41 | "name": "link", 42 | "type": "url" 43 | } 44 | ] 45 | }] 46 | }, 47 | 48 | { 49 | "name": "msnnewsdetail", 50 | "description": "This item collects category, title, author, date and time of news", 51 | "viewGroup": "PInfo", 52 | "title": "msn News details", 53 | "url_match": "*://*.msn.com/*", 54 | "type": "event", 55 | "is_enabled": true, 56 | "events": [{ 57 | "selector": "window", 58 | "event_name": "DOMContentLoaded" 59 | }], 60 | "objects": [{ 61 | "selector": "document", 62 | "properties": [{ 63 | "selector": "h1", 64 | "property": "innerText", 65 | "name": "Title", 66 | "type": "text" 67 | }, 68 | { 69 | "selector": "#articleProviderMainLogo", 70 | "property": "alt", 71 | "name": "category", 72 | "type": "text" 73 | }, 74 | { 75 | "selector": "span.truncate", 76 | "property": "innerText", 77 | "name": "Author", 78 | "type": "text" 79 | }, 80 | { 81 | "selector": "time", 82 | "isRequired": true, 83 | "property": "innerText", 84 | "name": "Time", 85 | "type": "text" 86 | } 87 | ] 88 | 89 | }] 90 | } 91 | ] 92 | } -------------------------------------------------------------------------------- /js/modules/News/uol/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "news_uol", 3 | "description": "This module looks through all activities of a user on uol media and captures those activities that the user has permitted", 4 | "functions": [ 5 | "content" 6 | ], 7 | "is_enabled": true, 8 | "privacyLevel": 1, 9 | "anonymityLevel": 1 10 | } -------------------------------------------------------------------------------- /js/modules/News/uol/content.json: -------------------------------------------------------------------------------- 1 | { 2 | "content_matches": [ 3 | "*://*.uol.com.br/*" 4 | ], 5 | "content_mapping": { 6 | "win": "desktop", 7 | "mac": "desktop", 8 | "android": "desktop", 9 | "cros": "desktop", 10 | "openbsd": "desktop", 11 | "ios": "desktop", 12 | "ipados": "desktop" 13 | }, 14 | "desktop": [{ 15 | "name": "uolLink", 16 | "description": "This item collects news title and news url after click", 17 | "viewGroup": "PInfo", 18 | "title": "uol News", 19 | "url_match": "*://*.uol.com.br/*", 20 | "type": "event", 21 | "is_enabled": true, 22 | "events": [{ 23 | "selector": "a", 24 | "event_name": "click" 25 | }, 26 | { 27 | "selector": "a", 28 | "event_name": "contextmenu" 29 | } 30 | ], 31 | "objects": [{ 32 | "selector": "", 33 | "properties": [{ 34 | "property": "innerText", 35 | "name": "title", 36 | "type": "text" 37 | }, 38 | { 39 | "property": "href", 40 | "name": "link", 41 | "type": "url" 42 | } 43 | ] 44 | }] 45 | }, 46 | { 47 | "name": "uolnewsdetail", 48 | "description": "This item collects category, title, author, date and time of news", 49 | "viewGroup": "PInfo", 50 | "title": "uol News details", 51 | "url_match": "*://*.uol.com.br/esporte/*", 52 | "type": "event", 53 | "is_enabled": true, 54 | "events": [{ 55 | "selector": "window", 56 | "event_name": "DOMContentLoaded" 57 | }], 58 | "objects": [ 59 | { 60 | "selector": "document", 61 | "properties": [{ 62 | "selector": "h1", 63 | "property": "innerText", 64 | "name": "Title", 65 | "type": "text" 66 | }, 67 | { 68 | "selector": ".title-name", 69 | "property": "innerText", 70 | "name": "category", 71 | "type": "text" 72 | }, 73 | { 74 | "selector": ".p-author.time", 75 | "isRequired": true, 76 | "property": "innerText", 77 | "name": "Time", 78 | "type": "text" 79 | }, 80 | 81 | { 82 | "selector": "p.p-author:not(.time)", 83 | "property": "innerText", 84 | "name": "Author", 85 | "type": "text" 86 | } 87 | ] 88 | 89 | 90 | }] 91 | }, 92 | { 93 | "name": "uolnewsdetail", 94 | "description": "This item collects category, title, author, date and time of news", 95 | "viewGroup": "PInfo", 96 | "title": "uol News details", 97 | "url_match": "*://noticias.uol.com.br/*", 98 | "type": "event", 99 | "is_enabled": true, 100 | "events": [{ 101 | "selector": "window", 102 | "event_name": "DOMContentLoaded" 103 | }], 104 | "objects": [{ 105 | "selector": "document", 106 | "properties": [{ 107 | "selector": "h1", 108 | "property": "innerText", 109 | "name": "Title", 110 | "type": "text" 111 | }, 112 | { 113 | "selector": ".title-name", 114 | "property": "innerText", 115 | "name": "category", 116 | "type": "text" 117 | }, 118 | { 119 | "selector": ".p-author.time", 120 | "isRequired": true, 121 | "property": "innerText", 122 | "name": "Time", 123 | "type": "text" 124 | }, 125 | 126 | { 127 | "selector": "p.p-author:not(.time)", 128 | "property": "innerText", 129 | "name": "Author", 130 | "type": "text" 131 | } 132 | 133 | ] 134 | 135 | }] 136 | }, 137 | { 138 | "name": "uolnewsdetail", 139 | "description": "This item collects category, title, author, date and time of news", 140 | "viewGroup": "PInfo", 141 | "title": "uol News details", 142 | "url_match": "*://*.uol.com.br/noticias/*", 143 | "type": "event", 144 | "is_enabled": true, 145 | "events": [{ 146 | "selector": "window", 147 | "event_name": "DOMContentLoaded" 148 | }], 149 | "objects": [{ 150 | "selector": "document", 151 | "properties": [{ 152 | "selector": "h1", 153 | "property": "innerText", 154 | "name": "Title", 155 | "type": "text" 156 | }, 157 | { 158 | "selector": ".title-name", 159 | "property": "innerText", 160 | "name": "category", 161 | "type": "text" 162 | }, 163 | { 164 | "selector": ".p-author.time", 165 | "isRequired": true, 166 | "property": "innerText", 167 | "name": "Time", 168 | "type": "text" 169 | }, 170 | 171 | { 172 | "selector": "p.p-author:not(.time)", 173 | "property": "innerText", 174 | "name": "Author", 175 | "type": "text" 176 | } 177 | 178 | ] 179 | 180 | }] 181 | } 182 | 183 | ] 184 | } -------------------------------------------------------------------------------- /js/modules/News/yahoo/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "news_yahoo", 3 | "description": "This module looks through all activities of a user on yahoo media and captures those activities that the user has permitted", 4 | "functions": [ 5 | "content" 6 | ], 7 | "is_enabled": true, 8 | "privacyLevel": 1, 9 | "anonymityLevel": 1 10 | } -------------------------------------------------------------------------------- /js/modules/News/yahoo/content.json: -------------------------------------------------------------------------------- 1 | { 2 | "content_matches": [ 3 | "*://*.yahoo.com/*" 4 | ], 5 | "content_mapping": { 6 | "win": "desktop", 7 | "mac": "desktop", 8 | "android": "desktop", 9 | "cros": "desktop", 10 | "openbsd": "desktop", 11 | "ios": "desktop", 12 | "ipados": "desktop" 13 | }, 14 | "desktop": [ 15 | { 16 | "name": "yahooLink", 17 | "description": "This item collects news title and news url after click", 18 | "viewGroup": "PInfo", 19 | "title": "Yahoo", 20 | "url_match": "*://*.yahoo.com/*", 21 | "type": "event", 22 | "is_enabled": true, 23 | "events": [{ 24 | "selector": "a", 25 | "event_name": "click" 26 | }, 27 | { 28 | "selector": "a", 29 | "event_name": "contextmenu" 30 | } 31 | ], 32 | "objects": [{ 33 | "selector": "", 34 | "properties": [{ 35 | "property": "innerText", 36 | "name": "title", 37 | "type": "text" 38 | }, 39 | { 40 | "property": "href", 41 | "name": "link", 42 | "type": "url" 43 | } 44 | ] 45 | }] 46 | }, 47 | { 48 | "name": "yahooDetails", 49 | "description": "This item collects category, title, author, date and time of news", 50 | "viewGroup": "PInfo", 51 | "title": "Yahoo", 52 | "url_match": "*://*.yahoo.com/*", 53 | "type": "event", 54 | "is_enabled": true, 55 | "events": [{ 56 | "selector": "window", 57 | "event_name": "DOMContentLoaded" 58 | }], 59 | "objects": [{ 60 | "selector": "document", 61 | "properties": [{ 62 | "selector": "h1:first-child", 63 | "property": "innerText", 64 | "name": "Title", 65 | "type": "text" 66 | }, 67 | { 68 | "selector": ".caas-attr-meta", 69 | "property": "innerText", 70 | "name": "Author", 71 | "type": "text" 72 | }, 73 | { 74 | "selector": "time:first-child", 75 | "property": "innerText", 76 | "name": "date", 77 | "type": "text" 78 | }, 79 | { 80 | "selector": ".caas-category-label:first-child", 81 | "property": "innerText", 82 | "name": "category", 83 | "type": "text" 84 | } 85 | ] 86 | 87 | }] 88 | }, 89 | 90 | { 91 | "name": "yahooDetail", 92 | "description": "This item collects category, title, author, date and time of news", 93 | "viewGroup": "PInfo", 94 | "title": "Yahoo News", 95 | "url_match": "*://*yahoo.com/news/*", 96 | "type": "event", 97 | "readyAt": "DOMChange", 98 | "observingTargetNode": "#homepage-viewer", 99 | "observingConfig": { 100 | "attributes": false, 101 | "childList": true, 102 | "subtree": true 103 | }, 104 | "is_enabled": true, 105 | "events": [{ 106 | "selector": "#homepage-viewer", 107 | "event_name": "mouseenter" 108 | }], 109 | "objects": [{ 110 | "selector": "article", 111 | "properties": [{ 112 | "selector": "h1", 113 | "property": "innerText", 114 | "name": "Title", 115 | "type": "text" 116 | }, 117 | { 118 | "selector": ".caas-attr-meta", 119 | "property": "innerText", 120 | "name": "Author", 121 | "type": "text" 122 | }, 123 | { 124 | "selector": ".caas-attr-time-style", 125 | "property": "innerText", 126 | "name": "time", 127 | "type": "text" 128 | } 129 | ] 130 | 131 | }] 132 | } 133 | ] 134 | } -------------------------------------------------------------------------------- /js/modules/News/yahooNews/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "news_yahooNews", 3 | "description": "This module looks through all activities of a user on yahooNews media and captures those activities that the user has permitted", 4 | "functions": [ 5 | "content" 6 | ], 7 | "is_enabled": true, 8 | "privacyLevel": 1, 9 | "anonymityLevel": 1 10 | } -------------------------------------------------------------------------------- /js/modules/News/yahooNews/content.json: -------------------------------------------------------------------------------- 1 | { 2 | "content_matches": [ 3 | "*://news.yahoo.com/*", 4 | "*://*.yahoo.co.jp/*" 5 | ], 6 | "content_mapping": { 7 | "win": "desktop", 8 | "mac": "desktop", 9 | "android": "desktop", 10 | "cros": "desktop", 11 | "openbsd": "desktop", 12 | "ios": "desktop", 13 | "ipados": "desktop" 14 | }, 15 | "desktop": [ 16 | { 17 | "name": "yahooNewsDetails", 18 | "description": "This item collects category, title, author, date and time of news", 19 | "viewGroup": "PInfo", 20 | "title": "Yahoo News", 21 | "url_match": "*://*yahoo.com/*", 22 | "type": "event", 23 | "readyAt": "DOMChange", 24 | "observingTargetNode": "article", 25 | "observingConfig": { 26 | "attributes": false, 27 | "childList": true, 28 | "subtree": true 29 | }, 30 | "is_enabled": true, 31 | "events": [{ 32 | "selector": "article", 33 | "event_name": "mouseenter" 34 | }], 35 | "objects": [{ 36 | "selector": "", 37 | "properties": [{ 38 | "selector": "h1", 39 | "property": "innerText", 40 | "name": "Title", 41 | "type": "text" 42 | }, 43 | { 44 | "selector": ".author.Mb\\(4px\\).D\\(ib\\)", 45 | "property": "innerText", 46 | "name": "Author", 47 | "type": "text" 48 | }, 49 | { 50 | "selector": "time", 51 | "property": "innerText", 52 | "name": "date", 53 | "type": "text" 54 | } 55 | ] 56 | 57 | }] 58 | } 59 | ] 60 | } -------------------------------------------------------------------------------- /js/modules/Search/aol/browsing.json: -------------------------------------------------------------------------------- 1 | { 2 | "browsing_filter": { 3 | "urls": [ 4 | "*://search.aol.com/aol/*" 5 | ] 6 | }, 7 | "browsing_extraInfoSpec": [], 8 | "items": [ 9 | { 10 | "name": "aolQuery", 11 | "title": "Search Query", 12 | "viewGroup": "AOL", 13 | "is_enabled": true, 14 | "description": "This item collects all search queries that a user enter in AOL search bar", 15 | "filter": { 16 | "urls": [ 17 | "*://search.aol.com/aol/*" 18 | ] 19 | }, 20 | "patterns": [ 21 | { 22 | "method": "GET", 23 | "url_pattern": "https:\\/\\/search\\.aol\\.com\\/aol\\/([^\\/\\?\\;]*)[\\?|\\;].*", 24 | "pattern_type": "regex", 25 | "param": [ 26 | { 27 | "type": "query", 28 | "key": "q", 29 | "name": "query" 30 | }, 31 | { 32 | "type": "regex", 33 | "group": 1, 34 | "name": "category" 35 | } 36 | ], 37 | "schems": [ 38 | { 39 | "jpath": "$.query", 40 | "type": "text" 41 | }, 42 | { 43 | "jpath": "$.category", 44 | "type": "text" 45 | } 46 | ] 47 | } 48 | ] 49 | } 50 | ] 51 | } -------------------------------------------------------------------------------- /js/modules/Search/aol/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "search_aol", 3 | "description": "This module Captures a user search queries, search results, and links clicked by the user for AOL", 4 | "functions": [ 5 | "browsing", 6 | "content" 7 | ], 8 | "is_enabled": true, 9 | "privacyLevel": 1, 10 | "anonymityLevel": 1 11 | } -------------------------------------------------------------------------------- /js/modules/Search/ask/browsing.json: -------------------------------------------------------------------------------- 1 | { 2 | "browsing_filter": { 3 | "urls": [ 4 | "*://www.ask.com/*" 5 | ] 6 | }, 7 | "browsing_extraInfoSpec": [], 8 | "items": [ 9 | { 10 | "name": "askQuery", 11 | "title": "Search Query", 12 | "is_enabled": true, 13 | "description": "This item collects all search queries that a user enter in Ask search bar", 14 | "filter": { 15 | "urls": [ 16 | "*://www.ask.com/*" 17 | ] 18 | }, 19 | "patterns": [ 20 | { 21 | "method": "GET", 22 | "url_pattern": "https:\\/\\/www\\.ask\\.com\\/(web|youtube)\\?.*", 23 | "pattern_type": "regex", 24 | "param": [ 25 | { 26 | "type": "query", 27 | "key": "q", 28 | "name": "query" 29 | }, 30 | { 31 | "type": "regex", 32 | "group": 1, 33 | "name": "category" 34 | } 35 | ], 36 | "schems": [ 37 | { 38 | "jpath": "$.query", 39 | "type": "text" 40 | }, 41 | { 42 | "jpath": "$.category", 43 | "type": "text" 44 | } 45 | ] 46 | } 47 | ] 48 | } 49 | ] 50 | } -------------------------------------------------------------------------------- /js/modules/Search/ask/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "search_ask", 3 | "description": "This module Captures a user search queries, search results, and links clicked by the user for top 7 search engines: Google, Bing, Yahoo, AOL, Ask, Baidu, and DuckDuckGo", 4 | "functions": [ 5 | "browsing", 6 | "content" 7 | ], 8 | "is_enabled": true, 9 | "privacyLevel": 1, 10 | "anonymityLevel": 1 11 | } -------------------------------------------------------------------------------- /js/modules/Search/baidu/browsing.json: -------------------------------------------------------------------------------- 1 | { 2 | "browsing_filter": { 3 | "urls": [ 4 | "*://*.baidu.com/*" 5 | ] 6 | }, 7 | "browsing_extraInfoSpec": [], 8 | "items": [ 9 | { 10 | "name": "baiduQuery", 11 | "title": "Search Query", 12 | "is_enabled": false, 13 | "description": "This item collects all search queries that a user enter in Baidu search bar", 14 | "filter": { 15 | "urls": [ 16 | "*://*.baidu.com/*" 17 | ] 18 | }, 19 | "patterns": [ 20 | { 21 | "method": "GET", 22 | "url_pattern": "http[s]?:\\/\\/(.*)\\.baidu\\.com\\/([sfqim]\\?|sf\\/|search).*", 23 | "pattern_type": "regex", 24 | "param": [ 25 | { 26 | "type": "query", 27 | "key": "wd", 28 | "name": "query" 29 | }, 30 | { 31 | "type": "query", 32 | "key": "kw", 33 | "name": "query" 34 | }, 35 | { 36 | "type": "query", 37 | "key": "word", 38 | "name": "query" 39 | }, 40 | { 41 | "type": "regex", 42 | "group": 1, 43 | "name": "category" 44 | } 45 | ], 46 | "schems": [ 47 | { 48 | "jpath": "$.query", 49 | "type": "text" 50 | }, 51 | { 52 | "jpath": "$.category", 53 | "type": "text" 54 | } 55 | ] 56 | } 57 | ] 58 | } 59 | ] 60 | } -------------------------------------------------------------------------------- /js/modules/Search/baidu/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "search_baidu", 3 | "description": "This module Captures a user search queries, search results, and links clicked by the user for Baidu", 4 | "functions": [ 5 | "browsing", 6 | "content" 7 | ], 8 | "is_enabled": true, 9 | "privacyLevel": 1, 10 | "anonymityLevel": 1 11 | } -------------------------------------------------------------------------------- /js/modules/Search/bing/browsing.json: -------------------------------------------------------------------------------- 1 | { 2 | "browsing_filter": { 3 | "urls": [ 4 | "*://www.bing.com/*" 5 | ] 6 | }, 7 | "browsing_extraInfoSpec": [], 8 | "items": [ 9 | { 10 | "name": "bingQuery", 11 | "title": "Search Query", 12 | "is_enabled": true, 13 | "description": "This item collects all search queries that a user enter in Bing search bar", 14 | "filter": { 15 | "urls": [ 16 | "*://www.bing.com/*" 17 | ] 18 | }, 19 | "patterns": [ 20 | { 21 | "method": "GET", 22 | "url_pattern": "https:\\/\\/www\\.bing\\.com\\/(([^\\/\\?\\;]*)\\/search)\\?.*", 23 | "pattern_type": "regex", 24 | "param": [ 25 | { 26 | "type": "query", 27 | "key": "q", 28 | "name": "query" 29 | }, 30 | { 31 | "type": "regex", 32 | "group": 2, 33 | "name": "category" 34 | } 35 | ], 36 | "schems": [ 37 | { 38 | "jpath": "$.query", 39 | "type": "text" 40 | }, 41 | { 42 | "jpath": "$.category", 43 | "type": "text" 44 | } 45 | ] 46 | }, 47 | { 48 | "method": "GET", 49 | "url_pattern": "https:\\/\\/www\\.bing\\.com\\/(shop|maps|search)\\?.*", 50 | "pattern_type": "regex", 51 | "param": [ 52 | { 53 | "type": "query", 54 | "key": "q", 55 | "name": "query" 56 | }, 57 | { 58 | "type": "regex", 59 | "group": 1, 60 | "name": "category" 61 | } 62 | ], 63 | "schems": [ 64 | { 65 | "jpath": "$.query", 66 | "type": "text" 67 | }, 68 | { 69 | "jpath": "$.category", 70 | "type": "text" 71 | } 72 | ] 73 | } 74 | ] 75 | } 76 | ] 77 | } -------------------------------------------------------------------------------- /js/modules/Search/bing/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "search_bing", 3 | "description": "This module Captures a user search queries, search results, and links clicked by the user for Bing", 4 | "functions": [ 5 | "browsing", 6 | "content" 7 | ], 8 | "is_enabled": true, 9 | "privacyLevel": 1, 10 | "anonymityLevel": 1 11 | } -------------------------------------------------------------------------------- /js/modules/Search/duckduckgo/browsing.json: -------------------------------------------------------------------------------- 1 | { 2 | "browsing_filter": { 3 | "urls": [ 4 | "*://duckduckgo.com/*" 5 | ] 6 | }, 7 | "browsing_extraInfoSpec": [], 8 | "items": [ 9 | { 10 | "name": "duckduckgoQuery", 11 | "title": "Search Query", 12 | "viewGroup": "DuckDuckGo", 13 | "is_enabled": true, 14 | "description": "This item collects all search queries that a user enter in DuckduckGo search bar", 15 | "filter": { 16 | "urls": [ 17 | "*://duckduckgo.com/*" 18 | ] 19 | }, 20 | "patterns": [ 21 | { 22 | "method": "GET", 23 | "url_pattern": "https:\\/\\/duckduckgo\\.com\\/((i|news|v)\\.js)?\\?.*", 24 | "pattern_type": "regex", 25 | "param": [ 26 | { 27 | "type": "query", 28 | "key": "q", 29 | "name": "query" 30 | }, 31 | { 32 | "type": "regex", 33 | "group": 2, 34 | "name": "category", 35 | "default": "web" 36 | } 37 | ], 38 | "schems": [ 39 | { 40 | "jpath": "$.query", 41 | "type": "text" 42 | }, 43 | { 44 | "jpath": "$.category", 45 | "type": "text" 46 | } 47 | ] 48 | } 49 | ] 50 | } 51 | ] 52 | } -------------------------------------------------------------------------------- /js/modules/Search/duckduckgo/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "search_duckduckgo", 3 | "description": "This module Captures a user search queries, search results, and links clicked by the user for DuckDuckGo", 4 | "functions": [ 5 | "browsing", 6 | "content" 7 | ], 8 | "is_enabled": true, 9 | "privacyLevel": 1, 10 | "anonymityLevel": 1 11 | } -------------------------------------------------------------------------------- /js/modules/Search/google/browsing.json: -------------------------------------------------------------------------------- 1 | { 2 | "browsing_filter": { 3 | "urls": [ 4 | "*://www.google.com/search?*" 5 | ] 6 | }, 7 | "browsing_extraInfoSpec": [], 8 | "items": [ 9 | { 10 | "name": "googleQuery", 11 | "title": "Search Query", 12 | "is_enabled": true, 13 | "description": "This item collects all search queries that a user enter in Google search bar", 14 | "filter": { 15 | "urls": [ 16 | "*://www.google.com/search?*" 17 | ] 18 | }, 19 | "patterns": [ 20 | { 21 | "method": "GET", 22 | "url_pattern": "*://www.google.com/search?*", 23 | "pattern_type": "wildcard", 24 | "param": [ 25 | { 26 | "type": "query", 27 | "key": "q", 28 | "name": "query" 29 | }, 30 | { 31 | "type": "query", 32 | "key": "tbm", 33 | "name": "category", 34 | "default": "web" 35 | } 36 | ], 37 | "schems": [ 38 | { 39 | "jpath": "$.query", 40 | "type": "text" 41 | }, 42 | { 43 | "jpath": "$.category", 44 | "type": "text" 45 | } 46 | ] 47 | } 48 | ] 49 | } 50 | ] 51 | } -------------------------------------------------------------------------------- /js/modules/Search/google/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "search_google", 3 | "description": "This module Captures a user search queries, search results, and links clicked by the user for Google", 4 | "functions": [ 5 | "browsing", 6 | "content" 7 | ], 8 | "is_enabled": true, 9 | "privacyLevel": 1, 10 | "anonymityLevel": 1 11 | } -------------------------------------------------------------------------------- /js/modules/Search/yahoo/browsing.json: -------------------------------------------------------------------------------- 1 | { 2 | "browsing_filter": { 3 | "urls": [ 4 | "*://*.yahoo.com/*" 5 | ] 6 | }, 7 | "browsing_extraInfoSpec": [], 8 | "items": [ 9 | { 10 | "name": "yahooQuery", 11 | "title": "Search Query", 12 | "is_enabled": true, 13 | "description": "This item collects all search queries that a user enter in Yahoo search bar", 14 | "filter": { 15 | "urls": [ 16 | "*://*.yahoo.com/*" 17 | ] 18 | }, 19 | "patterns": [ 20 | { 21 | "method": "GET", 22 | "url_pattern": "https:\\/\\/((.*)\\.)?search\\.yahoo\\.com\\/search.*", 23 | "pattern_type": "regex", 24 | "param": [ 25 | { 26 | "type": "query", 27 | "key": "p", 28 | "name": "query" 29 | }, 30 | { 31 | "type": "regex", 32 | "group": 2, 33 | "name": "category", 34 | "default": "web" 35 | } 36 | ], 37 | "schems": [ 38 | { 39 | "jpath": "$.query", 40 | "type": "text" 41 | }, 42 | { 43 | "jpath": "$.category", 44 | "type": "text" 45 | } 46 | ] 47 | } 48 | ] 49 | } 50 | ] 51 | } -------------------------------------------------------------------------------- /js/modules/Search/yahoo/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "search_yahoo", 3 | "description": "This module Captures a user search queries, search results, and links clicked by the user for Yahoo", 4 | "functions": [ 5 | "browsing", 6 | "content" 7 | ], 8 | "is_enabled": true, 9 | "privacyLevel": 1, 10 | "anonymityLevel": 1 11 | } -------------------------------------------------------------------------------- /js/modules/Shopping/amazon/browsing.json: -------------------------------------------------------------------------------- 1 | { 2 | "browsing_filter": { 3 | "urls": [ 4 | "https://www.amazon.com/*", 5 | "https://www.amazon.de/*", 6 | "https://www.amazon.nl/*" 7 | ] 8 | }, 9 | "browsing_extraInfoSpec": [], 10 | "items": [ 11 | { 12 | "name": "Page Visit", 13 | "title": "Visited pages", 14 | "description": "This item collects all pages in Amazon that user has visited", 15 | "target_listener": "inspectVisit", 16 | "is_enabled": true 17 | }, 18 | { 19 | "name": "Visiting Graph", 20 | "title": "Visiting Graph", 21 | "description": "This item collects all navigations that user has done in Amazon web pages", 22 | "target_listener": "inspectReferrer", 23 | "is_enabled": true 24 | } 25 | ] 26 | } -------------------------------------------------------------------------------- /js/modules/Shopping/amazon/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shopping_amazon", 3 | "description": "This module looks through all activities of a user on amazon and captures those activities that the user has permitted", 4 | "functions": [ 5 | "browsing", 6 | "content" 7 | ], 8 | "is_enabled": true, 9 | "privacyLevel": 1, 10 | "anonymityLevel": 1 11 | } -------------------------------------------------------------------------------- /js/modules/Shopping/ebay/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shopping_ebay", 3 | "description": "This module looks through all activities of a user on ebay and captures those activities that the user has permitted", 4 | "functions": [ 5 | "content" 6 | ], 7 | "is_enabled": true, 8 | "privacyLevel": 1, 9 | "anonymityLevel": 1 10 | } -------------------------------------------------------------------------------- /js/modules/Shopping/etsy/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shopping_etsy", 3 | "description": "This module looks through all activities of a user on etsy and captures those activities that the user has permitted", 4 | "functions": [ 5 | "content" 6 | ], 7 | "is_enabled": true, 8 | "privacyLevel": 1, 9 | "anonymityLevel": 1 10 | } -------------------------------------------------------------------------------- /js/modules/Shopping/flipkart/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shopping_flipkart", 3 | "description": "This module looks through all activities of a user on flipkart and captures those activities that the user has permitted", 4 | "functions": [ 5 | "content" 6 | ], 7 | "is_enabled": true, 8 | "privacyLevel": 1, 9 | "anonymityLevel": 1 10 | } -------------------------------------------------------------------------------- /js/modules/Shopping/target/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shopping_target", 3 | "description": "This module looks through all activities of a user on target and captures those activities that the user has permitted", 4 | "functions": [ 5 | "content" 6 | ], 7 | "is_enabled": true, 8 | "privacyLevel": 1, 9 | "anonymityLevel": 1 10 | } -------------------------------------------------------------------------------- /js/modules/Shopping/walmart/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shopping_wallmart", 3 | "description": "This module looks through all activities of a user on wallmart and captures those activities that the user has permitted", 4 | "functions": [ 5 | "content" 6 | ], 7 | "is_enabled": true, 8 | "privacyLevel": 1, 9 | "anonymityLevel": 1 10 | } -------------------------------------------------------------------------------- /js/modules/Social/facebook/browsing.json: -------------------------------------------------------------------------------- 1 | { 2 | "browsing_filter": { 3 | "urls": [ 4 | "https://www.facebook.com/*" 5 | ] 6 | }, 7 | "browsing_extraInfoSpec": [], 8 | "items": [ 9 | { 10 | "name": "Search", 11 | "title": "Facebook Search", 12 | "description": "This item collects all search queries that a user has entered on Facebook search bar", 13 | "is_enabled": true, 14 | "patterns": [ 15 | { 16 | "method": "GET", 17 | "url_pattern": "^https:\\/\\/www\\.facebook\\.com\\/search\\/top\\/.*", 18 | "pattern_type": "regex", 19 | "param": [ 20 | { 21 | "type": "query", 22 | "key": "q", 23 | "name": "query" 24 | } 25 | ], 26 | "schems": [ 27 | { 28 | "jpath": "$.query", 29 | "type": "text" 30 | } 31 | ] 32 | } 33 | ] 34 | }, 35 | { 36 | "name": "Page Visit", 37 | "title": "Links clicked by user", 38 | "description": "This item collects all pages in Facebook that a user has visited", 39 | "is_enabled": true, 40 | "target_listener": "inspectVisit" 41 | }, 42 | { 43 | "name": "Visiting Graph", 44 | "title": "Visiting Graph", 45 | "description": "This item collects all navigations that a user does in Facebook web pages", 46 | "viewGroup": "UX", 47 | "is_enabled": true, 48 | "target_listener": "inspectReferrer" 49 | } 50 | ] 51 | } -------------------------------------------------------------------------------- /js/modules/Social/facebook/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "social_facebook", 3 | "description": "This module looks through all activities of a user on Facebook and captures those activities that the user has permitted", 4 | "functions": [ 5 | "browsing" 6 | ], 7 | "is_enabled": true, 8 | "privacyLevel": 1, 9 | "anonymityLevel": 2 10 | } -------------------------------------------------------------------------------- /js/modules/Social/twitter/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "social_twitter", 3 | "description": "This module looks through all activities of a user on twitter and captures those activities that the user has permitted", 4 | "functions": [ 5 | "browsing" 6 | ], 7 | "is_enabled": true, 8 | "privacyLevel": 1, 9 | "anonymityLevel": 1 10 | } -------------------------------------------------------------------------------- /js/pageAction.js: -------------------------------------------------------------------------------- 1 | import {storageHelper} from './storageHelper.js'; 2 | import {filterUtils} from './filterUtils.js'; 3 | import {browserUtils} from './browserUtils.js'; 4 | import {memberManager} from "./memberManager.js"; 5 | 6 | var pageAction = (function() { 7 | async function isDomainFiltered(tabInfo) { 8 | let domain = new URL(tabInfo.url) 9 | let f = { 10 | value: `*://${domain.host}/*`, 11 | type: 'wildcard', 12 | internal: false 13 | }; 14 | let filter = await storageHelper.retrieveFilters(); 15 | for (let i in filter) { 16 | if (filter[i].value === f.value && filter[i].type === f.type && filter[i].internal === f.internal) { 17 | return true; 18 | } 19 | } 20 | return false; 21 | 22 | } 23 | 24 | async function isCurrentDomainFiltered() { 25 | let tabs = await browser.tabs.query({active: true, windowId: browser.windows.WINDOW_ID_CURRENT}); 26 | let tab = await browser.tabs.get(tabs[0].id); 27 | return isDomainFiltered(tab); 28 | } 29 | 30 | function loadIcons(url) { 31 | browserUtils.isMobileDevice().then(res => { 32 | if(!res) { 33 | storageHelper.retrieveConfigs().then(configs => { 34 | if(configs.is_enabled) { 35 | if (memberManager.isJoined() === true) { 36 | storageHelper.retrieveFilters().then(filters => { 37 | if(filterUtils.filter(url, filters)) 38 | browser.browserAction.setIcon({path: {"38":"icons/mono_mark_38.png", "19":"icons/mono_mark_19.png"}}); 39 | else 40 | browser.browserAction.setIcon({path: {"38":"icons/green_mark_38.png", "19":"icons/green_mark_19.png"}}); 41 | }); 42 | } else { 43 | browser.browserAction.setIcon({path: {"38":"icons/error_mark_38.png", "19":"icons/error_mark_19.png"}}); 44 | } 45 | } 46 | else { 47 | browser.browserAction.setIcon({path: {"38":"icons/mono_mark_38.png", "19":"icons/mono_mark_19.png"}}); 48 | } 49 | }); 50 | } 51 | }); 52 | } 53 | 54 | async function handleFilter() { 55 | let tabs = await browser.tabs.query({active: true, windowId: browser.windows.WINDOW_ID_CURRENT}); 56 | let tab = await browser.tabs.get(tabs[0].id); 57 | return isDomainFiltered(tab).then(res => { 58 | if(res) { 59 | removeFilter(tab); 60 | return false; 61 | } 62 | else { 63 | addFilter(tab); 64 | return true; 65 | } 66 | 67 | }) 68 | } 69 | 70 | function addFilter(tab) { 71 | let domain = new URL(tab.url) 72 | if(!domain.host || typeof domain.host ==='undefined' || domain.host === '') { 73 | return; 74 | } 75 | let f = { 76 | value: `*://${domain.host}/*`, 77 | type: 'wildcard', 78 | internal: false 79 | }; 80 | 81 | 82 | let allow = true; 83 | storageHelper.retrieveFilters().then(filter => { 84 | for (let i in filter) { 85 | if (filter[i].value === f.value) { 86 | allow = false; 87 | } 88 | } 89 | if (allow) { 90 | filter.push(f); 91 | storageHelper.storeFilters(filter).then(res => { 92 | loadIcons(tab.url); 93 | }) 94 | } 95 | }) 96 | } 97 | 98 | function removeFilter(tab) { 99 | let domain = new URL(tab.url) 100 | let f = { 101 | value: `*://${domain.host}/*`, 102 | type: 'wildcard', 103 | internal: false 104 | }; 105 | if(!f.value || f.value==='undefined') { 106 | return; 107 | } 108 | 109 | storageHelper.retrieveFilters().then(filters => { 110 | filters = filters.filter(fl => { 111 | if (fl.value !== f.value || fl.type !== f.type || fl.internal !== f.internal) { 112 | return fl; 113 | } 114 | }) 115 | 116 | storageHelper.storeFilters(filters).then(res => { 117 | loadIcons(tab.url); 118 | }); 119 | 120 | }) 121 | 122 | } 123 | 124 | return { 125 | isCurrentDomainFiltered, 126 | loadIcons, 127 | handleFilter, 128 | addFilter, 129 | removeFilter, 130 | }; 131 | 132 | }()); 133 | 134 | export {pageAction}; -------------------------------------------------------------------------------- /js/storageHelper.js: -------------------------------------------------------------------------------- 1 | import {utils} from './utils.js'; 2 | 3 | var storageHelper = (function () { 4 | 5 | var messages = {}; 6 | const functionList = ["content", "browsing", "apiCall", "context", "task"] 7 | 8 | function retrieveProfile() { 9 | return retrieveData("profile"); 10 | } 11 | 12 | function updateProfile(info) { 13 | return updateData("profile", info) 14 | } 15 | 16 | function retrieveFilters() { 17 | return retrieveData("filters"); 18 | } 19 | 20 | function retrieveConfigs() { 21 | return retrieveData("configs"); 22 | } 23 | 24 | function updateConfigs(info) { 25 | return updateData("configs", info); 26 | } 27 | 28 | function storeFilters(filters) { 29 | return updateData("filters", filters) 30 | } 31 | 32 | function retrieveModules() { 33 | return retrieveData("modules"); 34 | } 35 | 36 | function updateModules(info) { 37 | return updateData("modules", info) 38 | } 39 | 40 | async function removeModule(moduleName) { 41 | var info = await retrieveData("modules"); 42 | delete info[moduleName]; 43 | browser.storage.local.set({modules: info}); 44 | } 45 | 46 | function saveMessage(msg, id) { 47 | messages[id] = msg; 48 | } 49 | 50 | function removeMessage(id) { 51 | /* 52 | var info = await retrieveData("messages"); 53 | delete info[id]; 54 | browser.storage.local.set({messages:info});*/ 55 | delete messages[id]; 56 | } 57 | 58 | function retrieveMessages() { 59 | return messages; 60 | } 61 | 62 | async function storeAll(db) { 63 | await browser.storage.local.set(db); 64 | } 65 | 66 | 67 | function retrieveAll() { 68 | return browser.storage.local.get(); 69 | } 70 | 71 | async function updateData(key, info) { 72 | var data = await retrieveData(key); 73 | utils.jsonUpdate(data, info); 74 | let x = {}; 75 | x[key] = data; 76 | return browser.storage.local.set(x); 77 | } 78 | 79 | async function storeData(key, info) { 80 | let x = {}; 81 | x[key] = info; 82 | return browser.storage.local.set(x); 83 | } 84 | 85 | async function retrieveData(key) { 86 | let x = await browser.storage.local.get(key); 87 | return x[key]; 88 | } 89 | 90 | async function createTask(info) { 91 | var tasks = await retrieveData("tasks"); 92 | if (!tasks[info.moduleName]) 93 | tasks[info.moduleName] = {}; 94 | tasks[info.moduleName][info.name] = { 95 | startTime: info.startTime, 96 | taskId: info.taskId, 97 | endTime: -1, 98 | success: "unknown" 99 | } 100 | let x = {}; 101 | x["tasks"] = tasks; 102 | browser.storage.local.set(x); 103 | } 104 | 105 | async function endTask(info) { 106 | var tasks = await retrieveData("tasks"); 107 | if (!info || !tasks[info.moduleName] || !tasks[info.moduleName][info.name]) 108 | return; 109 | var res = Object.assign({}, tasks[info.moduleName][info.name]); 110 | delete tasks[info.moduleName][info.name]; 111 | 112 | let x = {}; 113 | x["tasks"] = tasks; 114 | browser.storage.local.set(x); 115 | return res; 116 | } 117 | 118 | async function loadAllModuleTaskIds(moduleName) { 119 | var tasks = await retrieveData("tasks"); 120 | return tasks[moduleName]; 121 | } 122 | 123 | function updateFunctionSettings(module, functionName, settings) { 124 | if (module.functions.includes(functionName)) { 125 | for (let item of module[functionName].items) { 126 | item.is_enabled = settings[functionName][item.name] 127 | } 128 | } 129 | } 130 | 131 | function updatePrivacyLevel(privacyLevel) { 132 | let key = "configs"; 133 | let info = {privacyLevel: privacyLevel} 134 | return updateData(key, info); 135 | } 136 | 137 | async function saveModuleSettings(moduleName, settings) { 138 | var modules = await retrieveData("modules"); 139 | let ret = modules[moduleName]; 140 | if (typeof settings.is_enabled != "undefined") 141 | ret.is_enabled = settings.is_enabled; 142 | for (let f of functionList) { 143 | if (typeof settings[f] != "undefined") 144 | updateFunctionSettings(ret, f, settings); 145 | } 146 | return browser.storage.local.set({modules: modules}); 147 | } 148 | 149 | async function getVersion() { 150 | let configs = await retrieveData("configs"); 151 | return configs.version; 152 | } 153 | 154 | function retrieveOnboarding() { 155 | return retrieveData("onboarding"); 156 | } 157 | 158 | function updateOnboarding(info) { 159 | return updateData("onboarding", info) 160 | } 161 | 162 | async function removeOnboarding(onboardingName) { 163 | let info = await retrieveData("onboarding"); 164 | delete info[onboardingName]; 165 | browser.storage.local.set({onboarding: info}); 166 | } 167 | 168 | return { 169 | retrieveProfile, 170 | updateProfile, 171 | retrieveConfigs, 172 | updateConfigs, 173 | retrieveModules, 174 | updateModules, 175 | updatePrivacyLevel, 176 | retrieveFilters, 177 | retrieveAll, 178 | storeAll, 179 | saveModuleSettings, 180 | retrieveData, 181 | updateData, 182 | storeData, 183 | storeFilters, 184 | saveMessage, 185 | removeMessage, 186 | retrieveMessages, 187 | removeModule, 188 | createTask, 189 | endTask, 190 | loadAllModuleTaskIds, 191 | getVersion, 192 | retrieveOnboarding, 193 | updateOnboarding, 194 | removeOnboarding 195 | }; 196 | }()); 197 | export {storageHelper}; -------------------------------------------------------------------------------- /js/stream.js: -------------------------------------------------------------------------------- 1 | import {databaseHelper} from './databaseHelper.js'; 2 | import {communityHelper} from './communityHelper.js' 3 | // Create the client and give the API key to use by default 4 | 5 | 6 | let stream = function(streamId) { 7 | 8 | let client = communityHelper.getStreamrClient(); 9 | // Wrap event generation and producion into this method 10 | function produceNewEvent(msg) { 11 | 12 | // Produce the event to the Stream 13 | 14 | client.publish(streamId, msg) 15 | .then(async () => { 16 | console.log("message published successfully"); 17 | await databaseHelper.updateMessageCount(msg.header.module); 18 | }) 19 | .catch((err) => { 20 | console.error(`"Error on publishing message: ${err}`) 21 | }) 22 | } 23 | return { 24 | produceNewEvent 25 | }; 26 | }; 27 | 28 | 29 | export {stream}; 30 | 31 | -------------------------------------------------------------------------------- /js/swashApiHelper.js: -------------------------------------------------------------------------------- 1 | import {communityHelper} from "./communityHelper.js"; 2 | import {storageHelper} from "./storageHelper.js"; 3 | import {configManager} from "./configManager.js"; 4 | 5 | let swashApiHelper = (function () { 6 | let APIConfigManager; 7 | function init() { 8 | APIConfigManager = configManager.getConfig('swashAPI'); 9 | } 10 | 11 | async function callSwashAPIData(api, method='GET', body=undefined) { 12 | const url = APIConfigManager.endpoint + api 13 | let req = { 14 | method: method, 15 | headers: { 16 | 'Content-Type': 'application/json', 17 | 'Authorization': "Bearer ".concat(await communityHelper.generateJWT()) 18 | }, 19 | } 20 | 21 | if (body){ 22 | req = {...req, body: JSON.stringify(body)} 23 | } 24 | try { 25 | const resp = await fetch(url, req); 26 | const result = (await resp.json()); 27 | if (result.status === 'success') 28 | return result.data; 29 | else { 30 | console.log(result.message) 31 | return {reason: result.message} 32 | } 33 | } catch (err) { 34 | console.error(`Error message: ${err.message}`) 35 | } 36 | return {}; 37 | } 38 | 39 | async function isJoinedSwash() { 40 | const data = await callSwashAPIData(APIConfigManager.APIs.userJoin); 41 | if (data.id) { 42 | await updateUserId(data.id); 43 | return true; 44 | } 45 | return false; 46 | } 47 | 48 | async function joinSwash() { 49 | browser.tabs.create({ 50 | url: 'https://swashapp.io/user/join?token='.concat(await communityHelper.generateJWT()) 51 | }); 52 | } 53 | 54 | async function getReferralRewards() { 55 | const data = await callSwashAPIData(APIConfigManager.APIs.userReferralReward); 56 | if (data.reward) { 57 | return ethers.utils.formatEther(data.reward); 58 | } 59 | return '0'; 60 | } 61 | 62 | async function getWithdrawBalance() { 63 | const data = await callSwashAPIData(APIConfigManager.APIs.balanceWithdraw); 64 | const result = {}; 65 | 66 | if (data.sponsor && data.sponsor.minimum) { 67 | result.minimum = Number(ethers.utils.formatEther(data.sponsor.minimum)) 68 | } 69 | if (data.gas && data.gas.etherEquivalent) { 70 | result.gas = Number(ethers.utils.formatEther(data.gas.etherEquivalent)) 71 | } 72 | return result; 73 | } 74 | 75 | async function withdrawToTarget(recipient, amount, useSponsor, sendToMainnet) { 76 | const signature = await communityHelper.signWithdrawAllTo(recipient); 77 | if (!signature.error) { 78 | const amountInWei = ethers.utils.parseEther(amount); 79 | const body = { 80 | recipient: recipient, 81 | signature: signature, 82 | amount: amountInWei.toString(), 83 | useSponsor: useSponsor, 84 | sendToMainnet: sendToMainnet 85 | }; 86 | const data = await callSwashAPIData(APIConfigManager.APIs.userBalanceWithdraw, 'POST', body); 87 | if (data.tx) 88 | return data 89 | else if (data.message) { 90 | const tx = await communityHelper.transportMessage(message) 91 | return {tx: tx.transactionHash}; 92 | } 93 | return data; 94 | } 95 | return signature; 96 | } 97 | 98 | async function claimRewards() { 99 | return await callSwashAPIData(APIConfigManager.APIs.userReferralClaim, 'POST'); 100 | } 101 | 102 | async function getActiveReferral() { 103 | return await callSwashAPIData(APIConfigManager.APIs.referralActive); 104 | } 105 | 106 | async function ip2Location() { 107 | const data = await callSwashAPIData(APIConfigManager.APIs.ipLookup); 108 | if (data.country) { 109 | return {country: data.country, city: data.city}; 110 | } 111 | return undefined; 112 | } 113 | 114 | async function getDataEthPairPrice() { 115 | const url = 'https://api.binance.com/api/v3/ticker/price?symbol=DATAETH' 116 | const req = { 117 | method: 'GET' 118 | } 119 | try { 120 | const resp = await fetch(url, req); 121 | if (resp.status === 200) { 122 | let data = (await resp.json()); 123 | return data['price']; 124 | } 125 | } catch (err) { 126 | console.error(`Error message: ${err.message}`) 127 | } 128 | throw new Error('Unable to fetch DATA price'); 129 | } 130 | 131 | async function getUserId() { 132 | let profile = await storageHelper.retrieveProfile(); 133 | if (profile.user_id) 134 | return profile.user_id; 135 | return -1; 136 | } 137 | 138 | async function updateUserId(user_id) { 139 | let profile = await storageHelper.retrieveProfile(); 140 | if (profile.user_id == null || profile.user_id !== user_id) { 141 | profile.user_id = user_id; 142 | await storageHelper.updateProfile(profile); 143 | } 144 | } 145 | 146 | async function getUserCountry() { 147 | let profile = await storageHelper.retrieveProfile(); 148 | if (profile.country) { 149 | return {country: profile.country, city: profile.city}; 150 | } 151 | 152 | try { 153 | let {country, city} = await ip2Location(); 154 | if (country !== '') { 155 | profile.country = country; 156 | profile.city = city; 157 | await storageHelper.updateProfile(profile); 158 | return country; 159 | } 160 | } catch (err) { 161 | console.log(err.message); 162 | } 163 | return 'Unknown'; 164 | } 165 | 166 | return { 167 | joinSwash, 168 | isJoinedSwash, 169 | getReferralRewards, 170 | getActiveReferral, 171 | withdrawToTarget, 172 | claimRewards, 173 | getWithdrawBalance, 174 | getDataEthPairPrice, 175 | getUserId, 176 | getUserCountry, 177 | init 178 | }; 179 | }()); 180 | 181 | export {swashApiHelper}; 182 | -------------------------------------------------------------------------------- /js/utils.js: -------------------------------------------------------------------------------- 1 | var utils = (function() { 2 | 'use strict'; 3 | 4 | function notify(message) { 5 | /*browser.notifications.create({ 6 | "type": "basic", 7 | "iconUrl": browser.extension.getURL("icons/surf48.png"), 8 | "title": message.header.module + ":" + message.header.function + ":" + message.header.collector, 9 | "message": JSON.stringify(message) 10 | });*/ 11 | } 12 | 13 | function jsonUpdate(src, newObj) { 14 | if(Array.isArray(newObj)) 15 | { 16 | src.length = 0 17 | for(let item of newObj) 18 | src.push(item); 19 | return; 20 | } 21 | for (let prop in newObj) { 22 | if (newObj.hasOwnProperty(prop)) { 23 | let val = newObj[prop]; 24 | if (val != null && typeof val == "object") {// this also applies to arrays or null! 25 | if (Array.isArray(val)) { 26 | src[prop] = val; 27 | } else { 28 | if (typeof src === "string"){ 29 | src = val; 30 | return; 31 | } 32 | if (!src[prop]) 33 | src[prop] = {}; 34 | jsonUpdate(src[prop], val); 35 | } 36 | } else 37 | src[prop] = val; 38 | } 39 | } 40 | 41 | } 42 | 43 | function arrayRemove(arr, value) { 44 | return arr.filter(function(ele){ 45 | return ele != value; 46 | }); 47 | } 48 | 49 | 50 | function isEmpty(obj) { 51 | 52 | // null and undefined are "empty" 53 | if (obj == null) return true; 54 | 55 | // Assume if it has a length property with a non-zero value 56 | // that that property is correct. 57 | if (obj.length > 0) return false; 58 | if (obj.length === 0) return true; 59 | 60 | // If it isn't an object at this point 61 | // it is empty, but it can't be anything *but* empty 62 | // Is it empty? Depends on your application. 63 | if (typeof obj !== "object") return true; 64 | 65 | // Otherwise, does it have any properties of its own? 66 | // Note that this doesn't handle 67 | // toString and valueOf enumeration bugs in IE < 9 68 | for (var key in obj) { 69 | if (hasOwnProperty.call(obj, key)) return false; 70 | } 71 | 72 | return true; 73 | } 74 | 75 | function uuid() { 76 | function randomDigit() { 77 | if (crypto && crypto.getRandomValues) { 78 | var rands = new Uint8Array(1); 79 | crypto.getRandomValues(rands); 80 | return (rands[0] % 16).toString(16); 81 | } else { 82 | return ((Math.random() * 16) | 0).toString(16); 83 | } 84 | } 85 | var crypto = window.crypto || window.msCrypto; 86 | return 'xxxxxxxx-xxxx-4xxx-8xxx-xxxxxxxxxxxx'.replace(/x/g, randomDigit); 87 | } 88 | 89 | function wildcard(input, wc) { 90 | function regExpEscape (s) { 91 | return s.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&'); 92 | } 93 | var regex = new RegExp('^' + wc.split(/\*+/).map(regExpEscape).join('.*') + '$'); 94 | if(!input.match(regex)) 95 | return null; 96 | return input; 97 | } 98 | 99 | function serialize(obj) { 100 | var str = []; 101 | for(var p in obj) 102 | if (obj.hasOwnProperty(p)) { 103 | str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p])); 104 | } 105 | return str.join("&"); 106 | } 107 | 108 | return { 109 | jsonUpdate, 110 | wildcard, 111 | notify, 112 | uuid, 113 | serialize, 114 | isEmpty, 115 | arrayRemove 116 | }; 117 | }()); 118 | export {utils}; 119 | -------------------------------------------------------------------------------- /lib/jsonpointer.js: -------------------------------------------------------------------------------- 1 | !function(e,n){"function"==typeof define&&define.amd?define([],n):"object"==typeof module&&module.exports?module.exports=n():e.returnExports=n()}("undefined"!=typeof self?self:this,function(){var e=this,n=this.JsonPointer;function a(e,n,r){for(var t=e.toString(),i="",o=t,u=0,f=-1;-1<(f=o.indexOf(n));)i+=t.substring(u,u+f)+r,o=o.substring(f+n.length,o.length),u+=f+n.length;return 0s){if(f===u)return c=i[s],i[s]=n,c;i=i[s]}else if(i.length===s){if(f===u)return i.push(n),l;t&&(i=i[s]={})}}else{if(void 0===i[a]){if(t){if(f===u)return i[a]=n,l;if(-1!==g(i[a],r[f+1])){i=i[a]=[];continue}i=i[a]={};continue}return l}if(f===u)return c=i[a],i[a]=n,c;i=i[a]}return i}function c(e){return(n=e)&&n.length&&"#"===n[0]?r:t;var n}function p(e){var n,r,t,i,o=Array.isArray(e)?e.slice(0):e=c(e)(e),u=Array.isArray(e)?y(o):e,f=(i="if (typeof(obj) !== 'undefined'",0===(t=o).length?function(e){return e}:(i=t.reduce(function(e,n,r){return e+" && \n\ttypeof((obj = obj['"+a(t[r],"\\","\\\\")+"'])) !== 'undefined'"},"if (typeof(obj) !== 'undefined'"),i+=") {\n\treturn obj;\n }",new Function(["obj"],i)));Object.defineProperties(this,{get:{enumerable:!0,value:f},set:{enumerable:!0,value:function(e,n,r){return s(e,n,o,r)}},has:{enumerable:!0,value:function(e){return void 0!==f(e)}},path:{enumerable:!0,get:function(){return o.slice(0)}},pointer:{enumerable:!0,get:function(){return n||(n=y(o)),n}},uriFragmentIdentifier:{enumerable:!0,get:function(){return r||(r=d(o)),r}},toString:{enumerable:!0,configurable:!0,writable:!0,value:function(){return u}}})}function b(e){var n="string"==typeof e||Array.isArray(e)?new p(e):e;Object.defineProperties(this,{$ref:{enumerable:!0,value:n.uriFragmentIdentifier},resolve:{enumerable:!0,value:function(e){return n.get(e)}},toString:{enumerable:!0,writable:!0,configurable:!0,value:function(){return n.uriFragmentIdentifier}}})}function i(e,n,r){var t,i,o,u,f,a,s,c,l,g=[],h=0;for(g.push({obj:e,path:[]}),r&&(l=Object.create(null)),n(y([]),e);hu))break;r=r[u]}else r=r[o];return i===t&&void 0!==r}(e,c(n)(n))},p.get=function(e,n){return function(e,n){var r,t,i,o,u;if(void 0!==e){if(r=e,i=-1,t=n.length)for(;++iu))return;r=r[u]}else r=r[o];return r}}(e,c(n)(n))},p.set=function(e,n,r,t){return s(e,r,c(n)(n),t)},p.list=function(e,n){var r=[];return i(e,n?function(e,n){r.push({fragmentId:d(t(e)),value:n})}:function(e,n){r.push({pointer:e,value:n})}),r},p.flatten=function(e,n){var r={};return i(e,n?function(e,n){r[d(t(e))]=n}:function(e,n){r[e]=n}),r},p.map=function(e,n){var r=[];return i(e,n?function(e,n){r.push({key:d(t(e)),value:n})}:r.set.bind(r)),r},p.visit=i,p.decode=function(e){return c(e)(e)},p.decodePointer=t,p.encodePointer=y,p.decodeUriFragmentIdentifier=r,p.encodeUriFragmentIdentifier=d,(p.JsonPointer=p).JsonReference=b,p.isReference=b.isReference,p.noConflict=function(){return e.JsonPointer=n,p},e.JsonPointer=p}); -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "applications": { 3 | "gecko": { 4 | "id": "authsaz@gmail.com" 5 | } 6 | }, 7 | 8 | "background": { 9 | "page": "background.html" 10 | }, 11 | 12 | "browser_action": { 13 | "browser_style": false, 14 | "default_icon": { 15 | "19": "icons/green_mark_19.png", 16 | "38": "icons/green_mark_38.png" 17 | }, 18 | "default_title": "Swash" 19 | }, 20 | 21 | "description": "Get paid for your data as you browse the web. Gain control and help create a better, more dignified internet.", 22 | 23 | "icons": { 24 | "48": "icons/green_mark_48.png", 25 | "96": "icons/green_mark_96.png", 26 | "128": "icons/green_mark_128.png" 27 | }, 28 | 29 | "manifest_version": 2, 30 | 31 | "name": "Swash", 32 | 33 | "homepage_url": "https://swashapp.io/", 34 | 35 | "permissions": ["clipboardRead","storage","bookmarks", "tabs", "webRequest", "", "webRequestBlocking", "downloads"], 36 | 37 | "content_security_policy": "script-src 'self' https://www.youtube.com/ https://s.ytimg.com/; object-src 'self';", 38 | 39 | "version": "1.3.2" 40 | } 41 | -------------------------------------------------------------------------------- /popup/fonts/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/popup/fonts/.DS_Store -------------------------------------------------------------------------------- /popup/fonts/roboto-mono-v7-latin-500.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/popup/fonts/roboto-mono-v7-latin-500.eot -------------------------------------------------------------------------------- /popup/fonts/roboto-mono-v7-latin-500.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/popup/fonts/roboto-mono-v7-latin-500.ttf -------------------------------------------------------------------------------- /popup/fonts/roboto-mono-v7-latin-500.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/popup/fonts/roboto-mono-v7-latin-500.woff -------------------------------------------------------------------------------- /popup/fonts/roboto-mono-v7-latin-500.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/popup/fonts/roboto-mono-v7-latin-500.woff2 -------------------------------------------------------------------------------- /popup/fonts/roboto-mono-v7-latin-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/popup/fonts/roboto-mono-v7-latin-regular.eot -------------------------------------------------------------------------------- /popup/fonts/roboto-mono-v7-latin-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/popup/fonts/roboto-mono-v7-latin-regular.ttf -------------------------------------------------------------------------------- /popup/fonts/roboto-mono-v7-latin-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/popup/fonts/roboto-mono-v7-latin-regular.woff -------------------------------------------------------------------------------- /popup/fonts/roboto-mono-v7-latin-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/popup/fonts/roboto-mono-v7-latin-regular.woff2 -------------------------------------------------------------------------------- /popup/fonts/roboto-v20-latin-500.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/popup/fonts/roboto-v20-latin-500.eot -------------------------------------------------------------------------------- /popup/fonts/roboto-v20-latin-500.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/popup/fonts/roboto-v20-latin-500.ttf -------------------------------------------------------------------------------- /popup/fonts/roboto-v20-latin-500.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/popup/fonts/roboto-v20-latin-500.woff -------------------------------------------------------------------------------- /popup/fonts/roboto-v20-latin-500.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/popup/fonts/roboto-v20-latin-500.woff2 -------------------------------------------------------------------------------- /popup/fonts/roboto-v20-latin-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/popup/fonts/roboto-v20-latin-regular.eot -------------------------------------------------------------------------------- /popup/fonts/roboto-v20-latin-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/popup/fonts/roboto-v20-latin-regular.ttf -------------------------------------------------------------------------------- /popup/fonts/roboto-v20-latin-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/popup/fonts/roboto-v20-latin-regular.woff -------------------------------------------------------------------------------- /popup/fonts/roboto-v20-latin-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/popup/fonts/roboto-v20-latin-regular.woff2 -------------------------------------------------------------------------------- /popup/svg/Data_default.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 51A4DE9B-78E5-44C0-BA5A-A2B7678EA0D2@1.00x 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /popup/svg/Data_hover.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | E4575E14-F05E-40C8-9120-B63562E325DF@1.00x 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /popup/svg/Help_hover.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | D4783393-6FD6-468F-ACB2-8CA7437D662B@1.00x 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /popup/svg/Icons _ Progress _ Loading finished _ small.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 2F5B532D-4251-4230-99D8-5F1E19E4C19F@1.00x 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /popup/svg/Message _ Nortification _ error state .png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/popup/svg/Message _ Nortification _ error state .png -------------------------------------------------------------------------------- /popup/svg/Settings_default.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 96C967EA-5931-43FC-A0AC-263EC9E88B8B@1.00x 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /popup/svg/Settings_hover.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 371AB9DA-CC54-4F65-BFDA-F60AF28546C2@1.00x 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /popup/svg/cog.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | C8271589-10BF-4596-9760-4E7A3B8BF143@1.00x 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /popup/svg/filter-active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/popup/svg/filter-active.png -------------------------------------------------------------------------------- /popup/svg/filter-default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/popup/svg/filter-default.png -------------------------------------------------------------------------------- /popup/svg/filter-hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/popup/svg/filter-hover.png -------------------------------------------------------------------------------- /popup/svg/filter-mono.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/popup/svg/filter-mono.png -------------------------------------------------------------------------------- /popup/svg/navigation-menu-3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 0CBF608E-E965-40B2-A3F0-343C788FDFF1@1.00x 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /popup/svg/question-circle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 08809C80-3CEB-447C-A796-7C8D53A4FC20@1.00x 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /popup/svg/small.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 63305D72-2DED-4F65-A566-7FEE4B873F27@1.00x 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /popup/webfonts/fa-brands-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/popup/webfonts/fa-brands-400.eot -------------------------------------------------------------------------------- /popup/webfonts/fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/popup/webfonts/fa-brands-400.ttf -------------------------------------------------------------------------------- /popup/webfonts/fa-brands-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/popup/webfonts/fa-brands-400.woff -------------------------------------------------------------------------------- /popup/webfonts/fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/popup/webfonts/fa-brands-400.woff2 -------------------------------------------------------------------------------- /popup/webfonts/fa-regular-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/popup/webfonts/fa-regular-400.eot -------------------------------------------------------------------------------- /popup/webfonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/popup/webfonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /popup/webfonts/fa-regular-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/popup/webfonts/fa-regular-400.woff -------------------------------------------------------------------------------- /popup/webfonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/popup/webfonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /popup/webfonts/fa-solid-900.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/popup/webfonts/fa-solid-900.eot -------------------------------------------------------------------------------- /popup/webfonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/popup/webfonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /popup/webfonts/fa-solid-900.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/popup/webfonts/fa-solid-900.woff -------------------------------------------------------------------------------- /popup/webfonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swashapp/swash/e80380f3ece3aa1a6e0459d1fb55114983a4a183/popup/webfonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /swash.sh: -------------------------------------------------------------------------------- 1 | echo "Welcome to Swash development" 2 | if [ $# == 0 ]; 3 | then 4 | printf "Usage: swash.sh command 5 | Commands: 6 | build Create an extension package from source 7 | test Run the test units 8 | sign Sign the extension so it can be installed in Firefox 9 | run Run the extension 10 | lint Validate the extension source 11 | docs Open the web-ext documentation in a browser 12 | " 13 | exit 14 | fi 15 | 16 | case "$1" in 17 | 'test') 18 | cp environment/test/manifest.json . 19 | web-ext run --ignore-files "dashboard*" "popup*" "swash.sh" "environment*" 20 | ;; 21 | 'run') 22 | cp environment/dev/manifest.json . 23 | web-ext run --ignore-files "test*" "swash.sh" "environment*" 24 | ;; 25 | *) 26 | cp environment/production/manifest.json . 27 | web-ext $1 --ignore-files "test*" "swash.sh" "environment*" 28 | ;; 29 | esac 30 | -------------------------------------------------------------------------------- /test/js/lib/mocha-run.js: -------------------------------------------------------------------------------- 1 | window.onload = function() { 2 | mocha.run(); 3 | } -------------------------------------------------------------------------------- /test/js/lib/mocha-setup.js: -------------------------------------------------------------------------------- 1 | mocha.setup('bdd'); 2 | mocha.checkLeaks(); -------------------------------------------------------------------------------- /test/js/unit/communityhelper.test.js: -------------------------------------------------------------------------------- 1 | import {communityHelper} from '../../../js/communityHelper.js' 2 | 3 | describe('communityHelper', function() { 4 | this.timeout(15000); 5 | describe('getEncryptedWallet', function() { 6 | it('Encrypt wallet using password 123', async function() { 7 | let password = "123" 8 | communityHelper.createWallet(); 9 | let eWallet = await communityHelper.getEncryptedWallet(password) 10 | expect(JSON.parse(eWallet).Crypto.ciphertext).toMatch(/^[0-9a-f]+$/); 11 | }); 12 | }); 13 | 14 | describe('decryptWallet', function() { 15 | it('Decrypt an encrypted wallet using password 123', async function() { 16 | let password = "123" 17 | let wallet1 = communityHelper.createWallet(); 18 | let eWallet = await communityHelper.getEncryptedWallet(password) 19 | let wallet2 = await communityHelper.decryptWallet(eWallet, password) 20 | expect(wallet1.privateKey).toEqual(wallet2.privateKey); 21 | }); 22 | }); 23 | 24 | describe('join', function() { 25 | it('Join to Swash community product', async function() { 26 | //communityHelper.createWallet(); 27 | let res = await communityHelper.join(); 28 | expect(res.state).toEqual("ACCEPTED"); 29 | }); 30 | }); 31 | 32 | describe('getBalance', function() { 33 | it('Get on chain balance', async function() { 34 | //communityHelper.createWallet(); 35 | let balance = await communityHelper.getBalance(); 36 | expect(parseFloat(balance)).toEqual(0); 37 | }); 38 | }); 39 | 40 | describe('getCumulativeEarnings', function() { 41 | it('Get cummlative earnings', async function() { 42 | //communityHelper.createWallet(); 43 | //await communityHelper.join(); 44 | let balance = await communityHelper.getCumulativeEarnings(); 45 | expect(parseFloat(balance)).toEqual(0); 46 | }); 47 | }); 48 | 49 | describe('getAvailableBalance', function() { 50 | it('Get on chain balance', async function() { 51 | //communityHelper.createWallet(); 52 | //await communityHelper.join(); 53 | let aBalance = await communityHelper.getAvailableBalance(); 54 | expect(parseFloat(aBalance)).toEqual(0); 55 | }); 56 | }); 57 | }); -------------------------------------------------------------------------------- /test/js/unit/databaseHelper.test.js: -------------------------------------------------------------------------------- 1 | import {databaseHelper} from '../../../js/databaseHelper.js' 2 | 3 | describe('databaseHelper', function() { 4 | before(async function() { 5 | await databaseHelper.init(); 6 | let message = {name: 'test'} 7 | await databaseHelper.insertMessage(message); 8 | }); 9 | 10 | describe('getMessageCount', function() { 11 | it('Get message count for Search module', async function() { 12 | let module = "Search" 13 | let count = await databaseHelper.getMessageCount(module) 14 | expect(count).toBeGreaterThanOrEqualTo(0); 15 | }); 16 | }); 17 | 18 | describe('getTotalMessageCount', function() { 19 | it('Get total message count', async function() { 20 | let count = await databaseHelper.getTotalMessageCount() 21 | expect(count).toBeGreaterThanOrEqualTo(0); 22 | }); 23 | }); 24 | 25 | describe('updateMessageCount', function() { 26 | it('Update message count for Search module', async function() { 27 | let module = "Search" 28 | let count1 = await databaseHelper.getMessageCount(module) 29 | await databaseHelper.updateMessageCount(module) 30 | let count2 = await databaseHelper.getMessageCount(module) 31 | expect(count2).toEqual(count1 + 1); 32 | }); 33 | }); 34 | 35 | describe('getLastSentDate', function() { 36 | it('Get the time for the last data sending', async function() { 37 | let sendDate = await databaseHelper.getLastSentDate() 38 | expect(sendDate).toBeGreaterThanOrEqualTo(0); 39 | }); 40 | }); 41 | 42 | describe('getAllMessages', function() { 43 | it('Get all messages stored in database', async function() { 44 | let messages = await databaseHelper.getAllMessages() 45 | expect(messages.length).toBeGreaterThanOrEqualTo(0); 46 | }); 47 | }); 48 | }); 49 | 50 | -------------------------------------------------------------------------------- /test/js/unit/filterUtils.test.js: -------------------------------------------------------------------------------- 1 | import {filterUtils} from '../../../js/filterUtils.js' 2 | 3 | describe('filterUtils', function() { 4 | describe('filter', function() { 5 | it('Exact filtering: expect filter', function() { 6 | let input = "https://swashapp.io" 7 | let filters = [{type: "exact", value: "https://swashapp.io"}] 8 | expect(filterUtils.filter(input, filters)).toEqual(true); 9 | }); 10 | 11 | it('Exact filtering: expect not filter', function() { 12 | let input = "https://swashapp.io/" 13 | let filters = [{type: "exact", value: "https://swashapp.io"}] 14 | expect(filterUtils.filter(input, filters)).toEqual(false); 15 | }); 16 | 17 | it('Wildcard filtering: expect filter', function() { 18 | let input = "https://swashapp.io" 19 | let filters = [{type: "wildcard", value: "*://swashapp.*"}] 20 | expect(filterUtils.filter(input, filters)).toEqual(true); 21 | }); 22 | 23 | it('Wildcard filtering: expect not filter', function() { 24 | let input = "https://www.swashapp.io" 25 | let filters = [{type: "wildcard", value: "*://swashapp.*"}] 26 | expect(filterUtils.filter(input, filters)).toEqual(false); 27 | }); 28 | 29 | it('Regex filtering: expect filter', function() { 30 | let input = "https://swashapp.io" 31 | let filters = [{type: "regex", value: "https?:\/\/swash.*\.(io|net|org)"}] 32 | expect(filterUtils.filter(input, filters)).toEqual(true); 33 | }); 34 | 35 | it('Regex filtering: expect not filter', function() { 36 | let input = "https://swashapp.com" 37 | let filters = [{type: "regex", value: "https?:\/\/swash.*\.(io|net|org)"}] 38 | expect(filterUtils.filter(input, filters)).toEqual(false); 39 | }); 40 | }); 41 | }); -------------------------------------------------------------------------------- /test/js/unit/storageHelper.test.js: -------------------------------------------------------------------------------- 1 | import {storageHelper} from '../../../js/storageHelper.js' 2 | 3 | describe('storageHelper', function() { 4 | 5 | describe('updateProfile', function() { 6 | it('Update the Swash profile', async function() { 7 | let info = {'test': 'swash'} 8 | await storageHelper.updateProfile(info) 9 | let profile = await browser.storage.local.get('profile'); 10 | expect(profile.profile.test).toEqual(info.test); 11 | }); 12 | }); 13 | 14 | describe('retrieveFilters', function() { 15 | it('Retrieve all internal and external filters', async function() { 16 | let filters = await storageHelper.retrieveFilters(); 17 | let sampleFilter = { value: "file:///*", type: "wildcard", internal: true }; 18 | expect(filters).toContain(sampleFilter); 19 | }); 20 | }); 21 | 22 | describe('retrieveConfigs', function() { 23 | it('Retrieve Swash configuration', async function() { 24 | let config = await storageHelper.retrieveConfigs(); 25 | expect(config.homepage_url).toEqual("https://swashapp.io/"); 26 | }); 27 | }); 28 | 29 | describe('updateConfigs', function() { 30 | it('Update Swash configuration', async function() { 31 | let info = {name: 'Swash2'} 32 | await storageHelper.updateConfigs(info); 33 | let config = await browser.storage.local.get('configs'); 34 | expect(config.configs.name).toEqual("Swash2"); 35 | }); 36 | }); 37 | 38 | describe('storeFilters', function() { 39 | it('Store filters', async function() { 40 | let filters1 = [{ internal: true, type: 'wildcard', value: 'file:///*' }] 41 | await storageHelper.storeFilters(filters1); 42 | let filters2 = await browser.storage.local.get('filters'); 43 | expect(filters2.filters).toContain(filters1[0]); 44 | }); 45 | }); 46 | 47 | describe('retrieveModules', function() { 48 | it('Retrieve all modules', async function() { 49 | let modules = await storageHelper.retrieveModules(); 50 | expect(modules['Search'].name).toEqual("Search"); 51 | }); 52 | }); 53 | 54 | describe('updateModules', function() { 55 | it('Update modules', async function() { 56 | let info = {'Twitter':{name:'zzz'}} 57 | await storageHelper.updateModules(info); 58 | let modules = await browser.storage.local.get('modules'); 59 | expect(modules.modules['Twitter'].name).toEqual("zzz"); 60 | }); 61 | }); 62 | 63 | describe('removeModule', function() { 64 | it('Remove Search module', async function() { 65 | let moduleName = 'Facebook' 66 | await storageHelper.removeModule(moduleName); 67 | let modules = await browser.storage.local.get('modules'); 68 | expect(modules.modules['Facebook']).toNotExist(); 69 | }); 70 | }); 71 | 72 | describe('updatePrivacyLevel', function() { 73 | it('Update privacy level', async function() { 74 | let config = await browser.storage.local.get('configs'); 75 | let privacyLevel = config.configs.privacyLevel; 76 | privacyLevel += 1; 77 | await storageHelper.updatePrivacyLevel(privacyLevel); 78 | let privacyLevel2 = (await browser.storage.local.get('configs')).configs.privacyLevel; 79 | expect(privacyLevel2).toEqual(privacyLevel); 80 | }); 81 | }); 82 | 83 | describe('saveModuleSettings', function() { 84 | it('Save module settings', async function() { 85 | let moduleName = 'Search' 86 | let settings = {is_enabled: false} 87 | await storageHelper.saveModuleSettings(moduleName, settings) 88 | let modules = await browser.storage.local.get('modules'); 89 | expect(modules.modules['Search'].is_enabled).toEqual(false); 90 | }); 91 | }); 92 | }); 93 | 94 | 95 | -------------------------------------------------------------------------------- /test/js/unit/utils.test.js: -------------------------------------------------------------------------------- 1 | import {utils} from '../../../js/utils.js' 2 | 3 | describe('utils', function() { 4 | describe('arrayRemove', function() { 5 | it('remove item from array', function() { 6 | let arr = [1,2,'test',4] 7 | 8 | arr = utils.arrayRemove(arr, 'test') 9 | expect(arr[2]).toEqual(4); 10 | }); 11 | }); 12 | 13 | describe('uuid', function() { 14 | it('generate a random uuid', function() { 15 | expect(utils.uuid()).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/); 16 | }); 17 | }); 18 | 19 | describe('serialize', function() { 20 | it('Serialize object properties', function() { 21 | let obj = { 22 | param1: 'test1', 23 | param2: 'test2', 24 | param3: 'test3' 25 | } 26 | expect(utils.serialize(obj)).toEqual("param1=test1¶m2=test2¶m3=test3"); 27 | }); 28 | 29 | it('Serialize and encode object properties', function() { 30 | let obj = { 31 | param1: 'test 1', 32 | param2: 'test/2', 33 | param3: 'test3' 34 | } 35 | expect(utils.serialize(obj)).toEqual("param1=test%201¶m2=test%2F2¶m3=test3"); 36 | }); 37 | }); 38 | 39 | 40 | describe('wildcard matching', function() { 41 | it('Matched case', function() { 42 | let wc = "*://www.test.*" 43 | let input = "https://www.test.org" 44 | expect(utils.wildcard(input, wc)).toEqual(input); 45 | }); 46 | 47 | it('Not matched case', function() { 48 | let wc = "*://www.test.*" 49 | let input = "https://test.org" 50 | expect(utils.wildcard(input, wc)).toNotEqual(input); 51 | }); 52 | }); 53 | 54 | describe('isEmpty', function() { 55 | it('Null value', function() { 56 | let val = null 57 | expect(utils.isEmpty(val)).toEqual(true); 58 | }); 59 | 60 | it('Zero length string', function() { 61 | let val = "" 62 | expect(utils.isEmpty(val)).toEqual(true); 63 | }); 64 | 65 | it('Zer length array', function() { 66 | let val = [] 67 | expect(utils.isEmpty(val)).toEqual(true); 68 | }); 69 | 70 | it('Object with no property', function() { 71 | let val = {} 72 | expect(utils.isEmpty(val)).toEqual(true); 73 | }); 74 | }); 75 | 76 | describe('jsonUpdate', function() { 77 | it('Update existed properties', function() { 78 | let src = { 79 | prop1: { 80 | val: 10 81 | } 82 | } 83 | 84 | let newObject = { 85 | prop1: { 86 | val: 20 87 | } 88 | } 89 | utils.jsonUpdate(src, newObject) 90 | expect(src.prop1.val).toEqual(20); 91 | }); 92 | 93 | it('Update not existed simple properties', function() { 94 | let src = { 95 | prop1: { 96 | } 97 | } 98 | 99 | let newObject = { 100 | prop1: { 101 | val: 20 102 | } 103 | } 104 | utils.jsonUpdate(src, newObject) 105 | expect(src.prop1.val).toEqual(20); 106 | }); 107 | 108 | it('Update not existed object properties', function() { 109 | let src = { 110 | } 111 | 112 | let newObject = { 113 | prop1: { 114 | val: 20 115 | } 116 | } 117 | utils.jsonUpdate(src, newObject) 118 | expect(src.prop1.val).toEqual(20); 119 | }); 120 | 121 | it('Update not existed array properties', function() { 122 | let src = { 123 | prop1: { 124 | } 125 | } 126 | 127 | let newObject = { 128 | prop1: { 129 | val: [10, 20] 130 | } 131 | } 132 | utils.jsonUpdate(src, newObject) 133 | expect(src.prop1.val[1]).toEqual(20); 134 | }); 135 | 136 | it('Update existed array properties', function() { 137 | let src = { 138 | prop1: { 139 | val: [50, 60] 140 | } 141 | } 142 | 143 | let newObject = { 144 | prop1: { 145 | val: [10, 20] 146 | } 147 | } 148 | utils.jsonUpdate(src, newObject) 149 | expect(src.prop1.val[1]).toEqual(20); 150 | }); 151 | 152 | it('Update existed but different array properties', function() { 153 | let src = { 154 | prop1: { 155 | val: [50, 60] 156 | } 157 | } 158 | 159 | let newObject = { 160 | prop1: { 161 | val: [10, 20] 162 | } 163 | } 164 | utils.jsonUpdate(src, newObject) 165 | expect(src.prop1.val[1]).toEqual(20); 166 | }); 167 | }); 168 | }); -------------------------------------------------------------------------------- /test/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Mocha Tests 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | --------------------------------------------------------------------------------