def _RunUpdateFlow(self, client_id): # Get the flows that should have been started and finish them. fd = aff4.FACTORY.Open(client_id.Add("flows"), token=self.token) flows = list(fd.ListChildren()) gui_test_lib.CreateFileVersion(client_id, "fs/os/c/a.txt", "Hello World", timestamp=gui_test_lib.TIME_0, token=self.token) gui_test_lib.CreateFolder(client_id, "fs/os/c/TestFolder", timestamp=gui_test_lib.TIME_0, token=self.token) gui_test_lib.CreateFolder(client_id, "fs/os/c/bin/TestBinFolder", timestamp=gui_test_lib.TIME_0, token=self.token) client_mock = action_mocks.ActionMock() for flow_urn in flows: flow_test_lib.TestFlowHelper(flow_urn, client_mock, client_id=client_id, token=self.token, check_flow_errors=False)
def testApprovalExpiry(self): """Tests that approvals expire after the correct time.""" client_id = self.SetupClient(0) gui_test_lib.CreateFileVersion(client_id, "fs/os/foo", token=self.token) with self.assertRaises(grr_api_errors.AccessForbiddenError): self.api.Client(client_id.Basename()).File("fs/os/foo").Get() with test_lib.FakeTime(100.0, increment=1e-3): self.RequestAndGrantClientApproval(client_id, requestor=self.token.username) # This should work now. self.api.Client(client_id.Basename()).File("fs/os/foo").Get() token_expiry = config.CONFIG["ACL.token_expiry"] # Make sure the caches are reset. self.ClearCache() # This is close to expiry but should still work. with test_lib.FakeTime(100.0 + token_expiry - 100.0): self.api.Client(client_id.Basename()).File("fs/os/foo").Get() # Make sure the caches are reset. self.ClearCache() # Past expiry, should fail. with test_lib.FakeTime(100.0 + token_expiry + 100.0): with self.assertRaises(grr_api_errors.AccessForbiddenError): self.api.Client(client_id.Basename()).File("fs/os/foo").Get()
def testNavigateToFileInFilesView(self): gui_test_lib.CreateFileVersion(self.client_id, "fs/os/foofolder/subfolder/barfile", "Hello VFS View".encode("utf-8"), timestamp=gui_test_lib.TIME_1) self.Open(f"/v2/clients/{self.client_id}") self.Click("css=a.collected-files-tab") self.WaitUntilContains("files", self.GetCurrentUrlPath) self.Click("css=mat-tree a:contains('foofolder')") self.Click("css=mat-tree a:contains('subfolder')") self.Click("css=table.directory-table td:contains('barfile')") self.WaitUntilContains("barfile", self.GetCurrentUrlPath) self.WaitUntilContains("st_size 14 B", self.GetText, "css=app-stat-view") self.Click("css=a.mat-tab-link:contains('Text content')") self.WaitUntilContains("text", self.GetCurrentUrlPath) self.WaitUntilContains("Hello VFS View", self.GetText, "css=app-file-details")
def testUrlSensitiveCharactersAreShownInTree(self): gui_test_lib.CreateFileVersion( self.client_id, "fs/os/c/foo?bar&oh/a&=?b.txt", "Hello World".encode("utf-8"), timestamp=gui_test_lib.TIME_1, token=self.token) # Open VFS view for client 1 on a specific location. self.Open("/#/clients/C.0000000000000001/vfs/fs/os/c/") # Wait until the folder gets selected and its information displayed in # the details pane. self.WaitUntil(self.IsElementPresent, "css=grr-file-details:contains('VFSDirectory')") # Click on the "foo?bar&oh" subfolder. self.Click("css=#_fs-os-c-foo_3Fbar_26oh a:visible") # Some more unicode testing. self.Click(u"css=tr:contains(\"a&=?b.txt\")") self.Click("css=li[heading=Download]") self.WaitUntil(self.IsElementPresent, "css=grr-file-details:contains('a&=?b.txt')") # Test the text viewer. self.Click("css=li[heading=TextView]") self.WaitUntilContains("Hello World", self.GetText, "css=div.monospace pre")
def testSimpleUnauthorizedAccess(self): """Tests that simple access requires a token.""" client_id = self.SetupClient(0) gui_test_lib.CreateFileVersion(client_id, "fs/os/foo") with self.assertRaises(grr_api_errors.AccessForbiddenError): self.api.Client(client_id).File("fs/os/foo").Get()
def testFolderPathWithUnicodeCharactersCanBeClicked(self): dirpath = "fs/os/home/user/foo/a看a" filepath = f"{dirpath}/bar/baz.txt" gui_test_lib.CreateFileVersion(self.client_id, filepath, b"foobar") self.Open(f"/#/clients/{self.client_id}/vfs/{dirpath}") self.Click("css=li > a:contains(\"a看a\")") self.Click("css=li > a:contains(\"bar\")") self.WaitUntil(self.IsElementPresent, "css=tr:contains(\"baz.txt\")")
def GenerateNotifications(cls, client_id, token): """Generates fake notifications of different notification types.""" session_id = flow_test_lib.StartFlow(discovery.Interrogate, client_id=client_id, creator=token.username) notification.Notify( token.username, rdf_objects.UserNotification.Type.TYPE_CLIENT_INTERROGATED, "Fake discovery message", rdf_objects.ObjectReference( reference_type=rdf_objects.ObjectReference.Type.CLIENT, client=rdf_objects.ClientReference( client_id=client_id.Basename()))) # ViewObject: VirtualFileSystem notification.Notify( token.username, rdf_objects.UserNotification.Type.TYPE_VFS_FILE_COLLECTED, "File fetch completed", rdf_objects.ObjectReference( reference_type=rdf_objects.ObjectReference.Type.VFS_FILE, vfs_file=rdf_objects.VfsFileReference( client_id=client_id.Basename(), path_type=rdf_objects.PathInfo.PathType.OS, path_components=["proc", "10", "exe"]))) gui_test_lib.CreateFileVersion(client_id, "fs/os/proc/10/exe", b"", timestamp=gui_test_lib.TIME_0, token=token) # ViewObject: Flow notification.Notify( token.username, rdf_objects.UserNotification.Type.TYPE_FLOW_RUN_COMPLETED, "Fake view flow message", rdf_objects.ObjectReference( reference_type=rdf_objects.ObjectReference.Type.FLOW, flow=rdf_objects.FlowReference(client_id=client_id.Basename(), flow_id=session_id))) # FlowError if data_store.RelationalDBEnabled(): flow_base.TerminateFlow(client_id.Basename(), session_id, "Fake flow error") else: with aff4.FACTORY.Open(client_id.Add("flows").Add(session_id), mode="rw", token=token) as flow_obj: flow_obj.GetRunner().Error("Fake flow error") return session_id
def testShowsVfsFileContents(self): gui_test_lib.CreateFileVersion(self.client_id, "fs/os/foo/barfile", "Hello VFS View".encode("utf-8"), timestamp=gui_test_lib.TIME_1) self.Open( f"/v2/clients/{self.client_id}(drawer:files/os/%2Ffoo%2Fbarfile)") self.WaitUntilContains("/foo/barfile", self.GetText, "css=mat-drawer") self.WaitUntilContains("Hello VFS View", self.GetText, "css=mat-drawer")
def _RunUpdateFlow(self, client_id): gui_test_lib.CreateFileVersion( client_id, "fs/os/c/a.txt", "Hello World".encode("utf-8"), timestamp=gui_test_lib.TIME_0) gui_test_lib.CreateFolder( client_id, "fs/os/c/TestFolder", timestamp=gui_test_lib.TIME_0) gui_test_lib.CreateFolder( client_id, "fs/os/c/bin/TestBinFolder", timestamp=gui_test_lib.TIME_0) flow_test_lib.FinishAllFlowsOnClient(client_id)
def testFolderPathCanContainUrlSensitiveCharacters(self): gui_test_lib.CreateFileVersion(self.client_id, "fs/os/c/foo?bar&oh/a&=?b.txt", "Hello World".encode("utf-8"), timestamp=gui_test_lib.TIME_1) # Open VFS view for client 1 on a location containing unicode characters. self.Open( "/#c=C.0000000000000001&main=VirtualFileSystemView&t=_fs-os-c" "-foo_3Fbar_26oh") # Check that the correct file is listed. self.WaitUntil(self.IsElementPresent, "css=tr:contains(\"a&=?b.txt\")")
def testShowsVfsFileStatInDrawer(self): gui_test_lib.CreateFileVersion(self.client_id, "fs/os/foo/barfile", "Hello VFS View".encode("utf-8"), timestamp=gui_test_lib.TIME_1) self.Open( f"/v2/clients/{self.client_id}(drawer:files/os/%2Ffoo%2Fbarfile/stat)" ) self.WaitUntilContains("barfile", self.GetText, "css=mat-drawer") self.assertContainsInOrder([ "SHA-256", "23406c404b29af3a449196db4833de182b9b955df14cef54fb6004189968c154" ], self.GetText("css=mat-drawer"))
def _RunUpdateFlow(self, client_id): gui_test_lib.CreateFileVersion( client_id, "fs/os/c/a.txt", "Hello World".encode("utf-8"), timestamp=gui_test_lib.TIME_0) gui_test_lib.CreateFolder( client_id, "fs/os/c/TestFolder", timestamp=gui_test_lib.TIME_0) gui_test_lib.CreateFolder( client_id, "fs/os/c/bin/TestBinFolder", timestamp=gui_test_lib.TIME_0) flow_test_lib.FinishAllFlowsOnClient( client_id, client_mock=action_mocks.MultiGetFileClientMock(), check_flow_errors=False)
def testClientApproval(self): """Tests that we can create an approval object to access clients.""" client_id = self.SetupClient(0) gui_test_lib.CreateFileVersion(client_id, "fs/os/foo") with self.assertRaises(grr_api_errors.AccessForbiddenError): self.api.Client(client_id).File("fs/os/foo").Get() self.RequestAndGrantClientApproval(client_id, requestor=self.token.username) self.api.Client(client_id).File("fs/os/foo").Get() # Move the clocks forward to make sure the approval expires. with test_lib.FakeTime( rdfvalue.RDFDatetime.Now() + config.CONFIG["ACL.token_expiry"], increment=1e-3): with self.assertRaises(grr_api_errors.AccessForbiddenError): self.api.Client(client_id).File("fs/os/foo").Get()
def GenerateNotifications(cls, client_id, username): """Generates fake notifications of different notification types.""" session_id = flow_test_lib.StartFlow(discovery.Interrogate, client_id=client_id, creator=username) notification.Notify( username, rdf_objects.UserNotification.Type.TYPE_CLIENT_INTERROGATED, "Fake discovery message", rdf_objects.ObjectReference( reference_type=rdf_objects.ObjectReference.Type.CLIENT, client=rdf_objects.ClientReference(client_id=client_id))) # ViewObject: VirtualFileSystem notification.Notify( username, rdf_objects.UserNotification.Type.TYPE_VFS_FILE_COLLECTED, "File fetch completed", rdf_objects.ObjectReference( reference_type=rdf_objects.ObjectReference.Type.VFS_FILE, vfs_file=rdf_objects.VfsFileReference( client_id=client_id, path_type=rdf_objects.PathInfo.PathType.OS, path_components=["proc", "10", "exe"]))) gui_test_lib.CreateFileVersion(client_id, "fs/os/proc/10/exe", b"", timestamp=gui_test_lib.TIME_0) # ViewObject: Flow notification.Notify( username, rdf_objects.UserNotification.Type.TYPE_FLOW_RUN_COMPLETED, "Fake view flow message", rdf_objects.ObjectReference( reference_type=rdf_objects.ObjectReference.Type.FLOW, flow=rdf_objects.FlowReference(client_id=client_id, flow_id=session_id))) # FlowError flow_base.TerminateFlow(client_id, session_id, "Fake flow error") return session_id
def testTriggersMultiGetFilesFlow(self): gui_test_lib.CreateFileVersion(self.client_id, "fs/os/foo/barfile", "Hello VFS View".encode("utf-8"), timestamp=gui_test_lib.TIME_1) self.Open( f"/v2/clients/{self.client_id}(drawer:files/os/%2Ffoo%2Fbarfile)") self.WaitUntilContains("/foo/barfile", self.GetText, "css=mat-drawer") self.Click("css=button.recollect") self.Click("css=.mat-drawer-backdrop") self.WaitUntilNot(self.IsElementPresent, "css=mat-drawer") self.WaitUntil( self.IsElementPresent, "css=flow-details:contains('MultiGetFile') .title:contains('/foo/barfile')" )
def TouchFile(self, client_id, path): gui_test_lib.CreateFileVersion(client_id=client_id, path=path, token=self.token)
def testRefreshFileStartsFlow(self): self.Open("/") self.Type("client_query", "C.0000000000000001") self.Click("client_query_submit") self.WaitUntilEqual(u"C.0000000000000001", self.GetText, "css=span[type=subject]") # Choose client 1. self.Click("css=td:contains('0001')") # Go to Browse VFS. self.Click("css=a:contains('Browse Virtual Filesystem')") self.Click("css=#_fs i.jstree-icon") self.Click("css=#_fs-os i.jstree-icon") self.Click("css=#_fs-os-c i.jstree-icon") # Test file versioning. self.WaitUntil(self.IsElementPresent, "css=#_fs-os-c-Downloads") self.Click("link=Downloads") # Select a file and start a flow by requesting a newer version. self.Click("css=tr:contains(\"a.txt\")") self.Click("css=li[heading=Download]") self.Click("css=button:contains(\"Collect from the client\")") # Create a new file version (that would have been created by the flow # otherwise) and finish the flow. client_id = rdf_client.ClientURN("C.0000000000000001") fd = aff4.FACTORY.Open(client_id.Add("flows"), token=self.token) # Make sure that the flow has started (when button is clicked, the HTTP # API request is sent asynchronously). def MultiGetFileStarted(): return transfer.MultiGetFile.__name__ in list( x.__class__.__name__ for x in fd.OpenChildren()) self.WaitUntil(MultiGetFileStarted) flows = list(fd.ListChildren()) client_mock = action_mocks.MultiGetFileClientMock() for flow_urn in flows: flow_test_lib.TestFlowHelper(flow_urn, client_mock, client_id=client_id, check_flow_errors=False, token=self.token) time_in_future = rdfvalue.RDFDatetime.Now() + rdfvalue.Duration("1h") # We have to make sure that the new version will not be within a second # from the current one, otherwise the previous one and the new one will # be indistinguishable in the UI (as it has a 1s precision when # displaying versions). with test_lib.FakeTime(time_in_future): gui_test_lib.CreateFileVersion( rdf_client.ClientURN("C.0000000000000001"), "fs/os/c/Downloads/a.txt", "The newest version!", timestamp=rdfvalue.RDFDatetime.Now(), token=self.token) # Once the flow has finished, the file view should update and add the # newly created, latest version of the file to the list. The selected # option should still be "HEAD". self.WaitUntilContains("HEAD", self.GetText, "css=.version-dropdown > option[selected]") # The file table should also update and display the new timestamp. self.WaitUntilContains(gui_test_lib.DateTimeString(time_in_future), self.GetText, "css=.version-dropdown > option:nth(1)") # The file table should also update and display the new timestamp. self.WaitUntil( self.IsElementPresent, "css=grr-file-table tbody > tr td:contains(\"%s\")" % (gui_test_lib.DateTimeString(time_in_future))) # Make sure the file content has changed. self.Click("css=li[heading=TextView]") self.WaitUntilContains("The newest version!", self.GetText, "css=div.monospace pre") # Go to the flow management screen and check that there was a new flow. self.Click("css=a:contains('Manage launched flows')") self.Click("css=grr-flows-list tr:contains('MultiGetFile')") self.WaitUntilContains(transfer.MultiGetFile.__name__, self.GetText, "css=#main_bottomPane") self.WaitUntilContains( "c/Downloads/a.txt", self.GetText, "css=#main_bottomPane table > tbody td.proto_key:contains(\"Path\") " "~ td.proto_value")
def testRefreshFileStartsFlow(self): self.Open("/#/clients/C.0000000000000001/vfs/fs/os/c/Downloads/") # Select a file and start a flow by requesting a newer version. self.Click("css=tr:contains(\"a.txt\")") self.Click("css=li[heading=Download]") self.Click("css=button:contains(\"Collect from the client\")") # Create a new file version (that would have been created by the flow # otherwise) and finish the flow. # Make sure that the flow has started (when button is clicked, the HTTP # API request is sent asynchronously). def MultiGetFileStarted(): return compatibility.GetName(transfer.MultiGetFile) in [ f.flow_class_name for f in data_store.REL_DB.ReadAllFlowObjects( client_id=self.client_id) ] self.WaitUntil(MultiGetFileStarted) flow_test_lib.FinishAllFlowsOnClient(self.client_id, check_flow_errors=False) time_in_future = rdfvalue.RDFDatetime.Now() + rdfvalue.DurationSeconds( "1h") # We have to make sure that the new version will not be within a second # from the current one, otherwise the previous one and the new one will # be indistinguishable in the UI (as it has a 1s precision when # displaying versions). gui_test_lib.CreateFileVersion(self.client_id, "fs/os/c/Downloads/a.txt", "The newest version!".encode("utf-8"), timestamp=time_in_future) # Once the flow has finished, the file view should update and add the # newly created, latest version of the file to the list. The selected # option should still be "HEAD". self.WaitUntilContains("HEAD", self.GetText, "css=.version-dropdown > option[selected]") # The file table should also update and display the new timestamp. self.WaitUntilContains(gui_test_lib.DateTimeString(time_in_future), self.GetText, "css=.version-dropdown > option:nth(1)") # The file table should also update and display the new timestamp. self.WaitUntil( self.IsElementPresent, "css=grr-file-table tbody > tr td:contains(\"%s\")" % (gui_test_lib.DateTimeString(time_in_future))) # Make sure the file content has changed. self.Click("css=li[heading=TextView]") self.WaitUntilContains("The newest version!", self.GetText, "css=div.monospace pre") # Go to the flow management screen and check that there was a new flow. self.Click("css=a:contains('Manage launched flows')") self.Click("css=grr-flows-list tr:contains('MultiGetFile')") self.WaitUntilContains(transfer.MultiGetFile.__name__, self.GetText, "css=#main_bottomPane") self.WaitUntilContains( "c/Downloads/a.txt", self.GetText, "css=#main_bottomPane table > tbody td.proto_key:contains(\"Path\") " "~ td.proto_value")