1# Copyright 2017 The Chromium OS Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import glob 6import logging 7import os 8import utils 9 10from autotest_lib.client.common_lib import error 11from autotest_lib.client.common_lib.cros import chrome 12from autotest_lib.client.cros.enterprise import enterprise_policy_base 13from autotest_lib.client.cros.input_playback import input_playback 14 15POLL_TIMEOUT = 5 16POLL_FREQUENCY = 0.5 17 18 19class policy_DisableScreenshots( 20 enterprise_policy_base.EnterprisePolicyTest): 21 version = 1 22 23 def initialize(self, **kwargs): 24 """Emulate a keyboard in order to play back the screenshot shortcut.""" 25 self._initialize_test_constants() 26 super(policy_DisableScreenshots, self).initialize(**kwargs) 27 self.player = input_playback.InputPlayback() 28 self.player.emulate(input_type='keyboard') 29 self.player.find_connected_inputs() 30 31 32 def _initialize_test_constants(self): 33 """Initialize test-specific constants, some from class constants.""" 34 self.POLICY_NAME = 'DisableScreenshots' 35 self._DOWNLOADS = '/home/chronos/user/Downloads/' 36 self._SCREENSHOT_PATTERN = 'Screenshot*' 37 self._SCREENSHOT_FILENAME = self._DOWNLOADS + self._SCREENSHOT_PATTERN 38 39 self.TEST_CASES = { 40 'DisableScreenshot_Block': True, 41 'False_Allow': False, 42 'NotSet_Allow': None 43 } 44 45 # Possible API methods to capture the screen 46 self.CAPTURE_CMDS = [ 47 'captureVisibleTab', 48 # TODO(timkovich): https://crbug.com/839630 49 # 'tabCapture', 50 # TODO(timkovich): https://crbug.com/817497 51 # 'desktopCapture' 52 ] 53 54 55 def _screenshot_file_exists(self): 56 """ 57 Checks if screenshot file was created by keyboard shortcut. 58 59 @returns boolean indicating if screenshot file was saved or not. 60 61 """ 62 try: 63 utils.poll_for_condition( 64 lambda: len(glob.glob(self._SCREENSHOT_FILENAME)) > 0, 65 timeout=POLL_TIMEOUT, 66 sleep_interval=POLL_FREQUENCY) 67 except utils.TimeoutError: 68 logging.info('Screenshot file not found.') 69 return False 70 71 logging.info('Screenshot file found.') 72 return True 73 74 75 def _delete_screenshot_files(self): 76 """Delete existing screenshot files, if any.""" 77 for filename in glob.glob(self._SCREENSHOT_FILENAME): 78 os.remove(filename) 79 80 81 def cleanup(self): 82 """Cleanup files created in this test, if any and close the player.""" 83 self._delete_screenshot_files() 84 self.player.close() 85 super(policy_DisableScreenshots, self).cleanup() 86 87 88 def _test_screenshot_shortcut(self, policy_value): 89 """ 90 Verify DisableScreenshots is enforced for the screenshot shortcut. 91 92 When DisableScreenshots policy value is undefined, screenshots shall 93 be captured via the keyboard shortcut Ctrl + F5. 94 When DisableScreenshots policy is set to True screenshots shall not 95 be captured. 96 97 @param policy_value: policy value for this case. 98 99 """ 100 logging.info('Deleting preexisting Screenshot files.') 101 self._delete_screenshot_files() 102 103 # Keyboard shortcut for screenshots 104 self.player.blocking_playback_of_default_file( 105 input_type='keyboard', filename='keyboard_ctrl+f5') 106 107 screenshot_file_captured = self._screenshot_file_exists() 108 if policy_value: 109 if screenshot_file_captured: 110 raise error.TestFail('Screenshot should not be captured') 111 elif not screenshot_file_captured: 112 raise error.TestFail('Screenshot should be captured') 113 114 115 def _test_screenshot_apis(self, policy_value): 116 """ 117 Verify DisableScreenshot policy blocks API calls. 118 119 Attempts to capture the screen using all of the methods to capture 120 the screen through the APIs. Captures should not happen when 121 policy_value is True and should happen in the other cases. 122 123 @param policy_value: policy value for this case 124 125 @raises error.TestFail: In the case where the capture behavior 126 does not match the policy value 127 128 """ 129 tab = self.navigate_to_url('https://google.com') 130 131 current_dir = os.path.dirname(os.path.realpath(__file__)) 132 133 for method in self.CAPTURE_CMDS: 134 # Set the document.title to the test name 135 tab.ExecuteJavaScript('document.title = "%s"' % method) 136 137 # Call the extension's shortcut to trigger the API call 138 self.player.blocking_playback( 139 input_type='keyboard', 140 filepath=os.path.join(current_dir, 'keyboard_ctrl+shift+y')) 141 142 # desktopCapture opens a prompt window that needs to be OKed 143 if method == 'desktopCapture': 144 self.player.blocking_playback_of_default_file( 145 input_type='keyboard', filename='keyboard_enter') 146 147 # The document.title is used to pass information to and from 148 # the DOM and the extension. The return value of the screenshot 149 # API call is set to the document.title. 150 try: 151 utils.poll_for_condition( 152 lambda: tab.EvaluateJavaScript( 153 'document.title != "%s"' % method 154 ), 155 timeout=POLL_TIMEOUT) 156 capture = tab.EvaluateJavaScript('document.title') 157 except utils.TimeoutError: 158 capture = None 159 160 if capture == 'undefined': 161 capture = None 162 163 if policy_value: 164 if capture is not None: 165 raise error.TestFail('Screen should not be captured. ' 166 'method = %s, capture = %s' 167 % (method, capture)) 168 elif capture is None: 169 raise error.TestFail('Screen should be captured. ' 170 'method = %s, capture = %s' 171 % (method, capture)) 172 173 174 def run_once(self, case): 175 """ 176 Setup and run the test configured for the specified test case. 177 178 @param case: Name of the test case to run. 179 180 """ 181 case_value = self.TEST_CASES[case] 182 self._extension_path = os.path.join(os.path.dirname(__file__), 183 'Screenshooter') 184 185 self.setup_case(user_policies={self.POLICY_NAME: case_value}, 186 extension_paths=[self._extension_path]) 187 188 self._test_screenshot_shortcut(case_value) 189 self._test_screenshot_apis(case_value) 190