Project

General

Profile

« Previous | Next » 

Revision 587c1a88

Added by koszko over 1 year ago

display an informative message in settings page if IndexedDB cannot be accessed

View differences:

html/settings.html
35 35
#LOADCSS html/base.css
36 36
#LOADCSS html/grid.css
37 37
    <style>
38
      #loader, #indexeddb_error {
39
	  margin: auto;
40
	  padding: 1em;
41
	  max-width: 800px;
42
      }
43
      #indexeddb_error p {
44
	  margin-bottom: 1em;
45
      }
46

  
38 47
      /* Style top menu items. */
39 48
      #tab_heads>* {
40 49
	  background-color: #70AF70;
......
114 123
#INCLUDE html/item_preview.html
115 124
#INCLUDE html/text_entry_list.html
116 125
#INCLUDE html/payload_create.html
117
    <ul id="tab_heads">
118
      <li id="blocking_head"> Blocking </li>
119
      <li id="mappings_head"> Mappings </li>
120
      <li id="resources_head"> Resources </li>
121
      <li id="new_payload_head" class="active_head"> New payload </li>
122
      <li id="repos_head"> Repositories </li>
123
    </ul>
124
    <div id="top_menu_line" class="top_line"></div>
125
    <div id="blocking_tab" class="tab">
126
      <div id="blocking_editable_container" class="grid_2">
127
	<div id="blocking_list_container">
128
	  <h3>Block scripts on</h3>
129
	</div>
130
	<div id="allowing_list_container">
131
	  <h3>Allow scripts on</h3>
126
    <div id="loader">
127
      Loading settings page...
128
    </div>
129
    <div id="indexeddb_error" class="hide">
130
      <p>
131
	Cannot display settings page.
132
      </p>
133
      <p>
134
	Haketilo could not access IndexedDB. IndexedDB is an in-browser
135
	database in which Haketilo stores all its configuration. Without it, the
136
	settings page is non-operational.
137
      <p>
138
#IF MOZILLA
139
	<div id="indexeddb_private_mode_explanation" class="hide">
140
	  <p>
141
	    This issue is the result of using Haketilo in Private Browsing mode.
142
	    For privacy reasons your browser blocks access to IndexedDB in
143
	    private windows and this unfortunately also affects Haketilo's
144
	    settings page.
145
	  </p>
146
	  <p>
147
	    You can sacrifice this single privacy feature and enable IndexedDB
148
	    access in private windows by navigating to "about:config" in the URL
149
	    bar, agreeing to accept the risk and setting the
150
	    "dom.indexedDB.privateBrowsing.enabled" preference to "true". Those
151
	    pages that have their scripts blocked will still be unable to access
152
	    IndexedDB.
153
	  </p>
154
	  <p>
155
	    Alternatively, you can open Haketilo's settings in a separate,
156
	    non-private window. The configuration you make there will take
157
	    effect on pages opened in Private Browsing mode as well.
158
	  </p>
132 159
	</div>
133
	<div id="default_policy_dialog" class="grid_col_both text_center">
160
#ENDIF
161
    </div>
162
    <div id="main_view" class="hide">
163
      <ul id="tab_heads">
164
	<li id="blocking_head"> Blocking </li>
165
	<li id="mappings_head"> Mappings </li>
166
	<li id="resources_head"> Resources </li>
167
	<li id="new_payload_head" class="active_head"> New payload </li>
168
	<li id="repos_head"> Repositories </li>
169
      </ul>
170
      <div id="top_menu_line" class="top_line"></div>
171
      <div id="blocking_tab" class="tab">
172
	<div id="blocking_editable_container" class="grid_2">
173
	  <div id="blocking_list_container">
174
	    <h3>Block scripts on</h3>
175
	  </div>
176
	  <div id="allowing_list_container">
177
	    <h3>Allow scripts on</h3>
178
	  </div>
179
	  <div id="default_policy_dialog" class="grid_col_both text_center">
134 180
#INCLUDE html/default_blocking_policy.html
181
	  </div>
135 182
	</div>
183
	<div id="blocking_dialog_container" class="hide"></div>
184
      </div>
185
      <div id="mappings_tab" class="tab"></div>
186
      <div id="resources_tab" class="tab"></div>
187
      <div id="new_payload_tab" class="tab active_tab"></div>
188
      <div id="repos_tab" class="tab">
189
	<div id="repos_list_container"></div>
190
	<div id="repos_dialog_container" class="hide"></div>
136 191
      </div>
137
      <div id="blocking_dialog_container" class="hide"></div>
138
    </div>
139
    <div id="mappings_tab" class="tab"></div>
140
    <div id="resources_tab" class="tab"></div>
141
    <div id="new_payload_tab" class="tab active_tab"></div>
142
    <div id="repos_tab" class="tab">
143
      <div id="repos_list_container"></div>
144
      <div id="repos_dialog_container" class="hide"></div>
145 192
    </div>
146 193
#LOADJS html/settings.js
147 194
  </body>
html/settings.js
41 41
 * proprietary program, I am not going to enforce this in court.
42 42
 */
43 43

  
44
#IMPORT common/indexeddb.js AS haketilodb
44 45
#IMPORT html/dialog.js
45 46

  
47
#IF MOZILLA
48
#FROM common/browser.js IMPORT browser
49
#ENDIF
50

  
46 51
#FROM html/DOM_helpers.js     IMPORT by_id
47 52
#FROM html/text_entry_list.js IMPORT blocking_allowing_lists, repo_list
48 53
#FROM html/item_list.js       IMPORT mapping_list, resource_list
......
118 123
    containers[0].append((await repo_list(dialog_ctx)).main_div);
119 124
}
120 125

  
121
set_up_blocking_tab();
122
set_up_mappings_tab();
123
set_up_resources_tab();
124
set_up_new_payload_tab();
125
set_up_repos_tab();
126
function set_up_settings_view() {
127
    by_id("loader").remove();
128
    by_id("main_view").classList.remove("hide");
129

  
130
    set_up_blocking_tab();
131
    set_up_mappings_tab();
132
    set_up_resources_tab();
133
    set_up_new_payload_tab();
134
    set_up_repos_tab();
135
}
136

  
137
#IF MOZILLA
138
async function show_indexeddb_error() {
139
    const this_tab = await browser.tabs.getCurrent();
140
    if (this_tab.incognito)
141
	by_id("indexeddb_private_mode_explanation").classList.remove("hide");
142
#ELSE
143
function show_indexeddb_error() {
144
#ENDIF
145
    by_id("loader").remove();
146
    by_id("indexeddb_error").classList.remove("hide");
147
}
148

  
149
async function init_settings_page() {
150
    try {
151
	await haketilodb.get();
152
    } catch(e) {
153
	console.error(e);
154
	show_indexeddb_error();
155
	return;
156
    }
157

  
158
    set_up_settings_view();
159
}
160

  
161
#IF UNIT_TEST
162
window.init_settings_page = init_settings_page;
163
#ELSE
164
init_settings_page();
165
#ENDIF
test/haketilo_test/test_integration.py
19 19

  
20 20
import pytest
21 21

  
22
from selenium.webdriver.support.ui import WebDriverWait
23
from selenium.webdriver.support import expected_conditions as EC
24
from selenium.webdriver.common.by import By
25

  
22 26
from .extension_crafting import get_extension_base_url
23 27

  
24 28
@pytest.mark.usefixtures('haketilo')
......
30 34
    base_url = get_extension_base_url(driver)
31 35
    driver.get(base_url + 'html/settings.html')
32 36

  
37
    WebDriverWait(driver, 10)\
38
        .until(EC.visibility_of_element_located((By.ID, "main_view")))
39

  
33 40
    for tab_head_id, item_text in [
34 41
            ('resources_head', 'Haketilo demonstrational script'),
35 42
            ('mappings_head',  'Haketilo demonstrational message'),
test/haketilo_test/unit/test_indexeddb.py
21 21
import json
22 22
from selenium.webdriver.common.by import By
23 23
from selenium.webdriver.support.ui import WebDriverWait
24
from selenium.webdriver.support import expected_conditions as EC
25 24
from selenium.common.exceptions import WebDriverException
26 25

  
27 26
from ..script_loader import load_script
test/haketilo_test/unit/test_settings.py
20 20
import pytest
21 21
from .utils import *
22 22

  
23
from selenium.webdriver.support.ui import WebDriverWait
24
from selenium.webdriver.support import expected_conditions as EC
25
from selenium.webdriver.common.by import By
26

  
23 27
from ..extension_crafting import ExtraHTML
24 28
from ..script_loader import load_script
25 29
from .utils import *
26 30

  
27
@pytest.mark.ext_data({
31
ext_data = {
28 32
    'background_script': broker_js,
29 33
    'extra_html': ExtraHTML('html/settings.html', wrap_into_htmldoc=False)
30
})
34
}
35

  
36
@pytest.mark.ext_data(ext_data)
31 37
@pytest.mark.usefixtures('webextension')
32 38
def test_settings_page_tabs(driver, execute_in_page):
33 39
    """
34
    Test navigation throught the tabs of the settings page.
40
    Test navigation through the tabs of the settings page.
35 41
    """
36 42
    # First, put some sample data in IndexedDB.
37 43
    execute_in_page(load_script('common/indexeddb.js'))
......
45 51
    # Now navigate to settings page.
46 52
    testpage_url = driver.execute_script('return window.location.href;')
47 53
    driver.get(testpage_url.replace('testpage.html', 'html/settings.html'))
54
    execute_in_page('init_settings_page();')
55

  
56
    WebDriverWait(driver, 10)\
57
        .until(EC.visibility_of_element_located((By.ID, "main_view")))
58

  
59
    assert driver.find_elements_by_id('loader') == []
60
    assert not driver.find_element_by_id('indexeddb_error').is_displayed()
48 61

  
49 62
    names = ['blocking', 'mappings', 'resources', 'new_payload', 'repos']
50 63
    tabs = dict([(n, driver.find_element_by_id(f'{n}_tab')) for n in names])
......
61 74
            assert 'active_head' not in heads[tab_name_2].get_attribute('class')
62 75
            assert 'active_tab' not in tabs[tab_name_2].get_attribute('class')
63 76
            assert not tabs[tab_name_2].is_displayed()
77

  
78
@pytest.mark.ext_data({
79
    **ext_data,
80
    'navigate_to': 'html/settings.html'
81
})
82
@pytest.mark.usefixtures('webextension')
83
@pytest.mark.parametrize('incognito', [True, False])
84
def test_settings_page_indexeddb_error(driver, execute_in_page, incognito):
85
    """
86
    Test if failure to access IndexedDB in settings page results in the
87
    appropriate message being shown.
88
    """
89
    execute_in_page(
90
        '''{
91
        /*
92
         * Mock an unavailable IndexedDB. Calling onerror() without having set
93
         * "errorCode" on the request is the behavior observed under Mozilla.
94
         */
95
        indexedDB.open = function() {
96
            const dummy_open_request = {};
97
            const dummy_event = {target: dummy_open_request};
98
            setTimeout(() => dummy_open_request.onerror(dummy_event), 0);
99

  
100
            return dummy_open_request;
101
        }
102

  
103
        const dummy_tab = {incognito: arguments[0]};
104
        browser.tabs.getCurrent = () => Promise.resolve(dummy_tab);
105

  
106
        init_settings_page();
107
        }''',
108
        incognito)
109

  
110
    WebDriverWait(driver, 10)\
111
        .until(EC.visibility_of_element_located((By.ID, 'indexeddb_error')))
112

  
113
    assert driver.find_elements_by_id('loader') == []
114
    assert not driver.find_element_by_id('main_view').is_displayed()
115

  
116
    if incognito:
117
        assert driver.find_element_by_id('indexeddb_private_mode_explanation')\
118
                     .is_displayed()

Also available in: Unified diff