def test__2(self): ''' Verify that append() unquotes the path, if requested to do so ''' self.assertEqual( utils_path.append('/foobar', 'foo%2fbaz', False), "/foobar/foo%2fbaz", ) self.assertEqual( utils_path.append('/foobar', 'foo%2fbaz', True), "/foobar/foo/baz", )
def test__4(self): ''' Verify that append() ASCII-fies the path in any case ''' self.assertEqual( utils_path.append("/foobar", six.u("'/cio\xe8'"), True), None ) self.assertEqual( utils_path.append("/foobar", six.u("'/cio%e8'"), True), None )
def test__1(self): ''' Make sure that append() fails when it can't decode the prefix or the path ''' # Note: '/cio\xc3a8' is wrong on purpose here self.assertEqual( utils_path.append(six.b('/cio\xc3a8'), '/foobar', False), None ) self.assertEqual( utils_path.append('/foobar', six.b('/cio\xc3\xa8'), False), None )
def api_results(stream, request, query): ''' Populates www/results.html page ''' dictionary = cgi.parse_qs(query) test = CONFIG['www_default_test_to_show'] if 'test' in dictionary: test = str(dictionary['test'][0]) # Read the directory each time, so you don't need to restart the daemon # after you have changed the description of a test. available_tests = {} for filename in os.listdir(TESTDIR): if filename.endswith('.json'): index = filename.rfind('.json') if index == -1: raise RuntimeError('api_results: internal error') name = filename[:index] available_tests[name] = filename if not test in available_tests: raise NotImplementedTest('Test not implemented') # Allow power users to customize results.html heavily, by creating JSON # descriptions with local modifications. filepath = utils_path.append(TESTDIR, available_tests[test], False) if not filepath: raise RuntimeError("api_results: append() path failed") localfilepath = filepath + '.local' if os.path.isfile(localfilepath): filep = open(localfilepath, 'rb') else: filep = open(filepath, 'rb') response_body = json.loads(filep.read()) filep.close() # Add extra information needed to populate results.html selection that # allows to select which test results must be shown. response_body['available_tests'] = available_tests.keys() response_body['selected_test'] = test descrpath = filepath.replace('.json', '.html') if os.path.isfile(descrpath): filep = open(descrpath, 'rb') response_body['description'] = filep.read() filep.close() # Provide the web user interface some settings it needs, but only if they # were not already provided by the `.local` file. for variable in COPY_CONFIG_VARIABLES: if not variable in response_body: response_body[variable] = CONFIG[variable] # Note: DO NOT sort keys here: order MUST be preserved indent, mimetype = None, 'application/json' if 'debug' in dictionary and utils.intify(dictionary['debug'][0]): indent, mimetype = 4, 'text/plain' response = Message() body = json.dumps(response_body, indent=indent) response.compose(code='200', reason='Ok', body=body, mimetype=mimetype) stream.send_response(request, response)
def signature_path(basedir, vinfo): ''' Return signature path ''' name = '.'.join([vinfo, 'tar', 'gz', 'sig']) path = utils_path.append(basedir, name, False) if not path: raise RuntimeError("updater_utils: append() path failed") return path
def test__3(self): ''' Verify that append() does not allow to go above the rootdir ''' self.assertEqual( utils_path.append('/foobar', '../etc/passwd', False), None ) self.assertEqual( utils_path.append('/foobar', six.b('\x2e\x2e\x2fetc\x2fpasswd'), False), None ) self.assertEqual( utils_path.append('/foobar', six.b('..%2fetc%2fpasswd'), True), None )
def install(self, ctx, body): ''' Install new version on Windows ''' # Make file names versiondir = utils_path.append(self.basedir, ctx['vinfo'], False) if not versiondir: raise RuntimeError("updater_win32: append() path failed") exefile = utils_path.join(versiondir, 'neubotw.exe') uninst = utils_path.join(versiondir, 'uninstall.exe') cmdline = '"%s" start' % exefile cmdline_k = '"%s" start -k' % exefile # # Overwrite the version of Neubot that is executed when # the user logs in. # regkey = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, "Software\Microsoft\Windows\CurrentVersion\Run", 0, _winreg.KEY_WRITE) _winreg.SetValueEx(regkey, "Neubot", 0, _winreg.REG_SZ, cmdline) _winreg.CloseKey(regkey) # Update the registry to reference the new uninstaller regkey = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, "Software\Microsoft\Windows\CurrentVersion\Uninstall\Neubot", 0, _winreg.KEY_WRITE) _winreg.SetValueEx(regkey, "DisplayName", 0, _winreg.REG_SZ, "Neubot " + utils_version.to_canonical(ctx['vinfo'])) _winreg.SetValueEx(regkey, "UninstallString", 0, _winreg.REG_SZ, uninst) _winreg.CloseKey(regkey) logging.info('updater_win32: updated win32 registry') # # Run the new version of Neubot and tell it that this # version should be stopped before proceeding with normal # startup. # # We need to close_fds, because the child process must # not inherit the parent handles. If it did, the listening # socket is inherited, and the child process cannot open # its own listening socket. The ``-k`` argument on the # command line instructs the child process to request this # process to exit. Of course the child does that before # attempting to listen a new socket. # logging.info('updater_win32: about to exec: %s', cmdline_k) subprocess.Popen(cmdline_k, close_fds=True)
def __verify(basedir, member): ''' Verify one member of the tarfile ''' # # Make sure that the combination of basedir and member # name falls below basedir. # utils_path.append(basedir, member.name) # # The tar archive should contain directories and # regular files only. # if not member.isdir() and not member.isreg(): raise RuntimeError('updater_install: %s: invalid type' % member.name) # # Make sure that the owner and group of the file is # root, as it should be. # if member.uid != 0 or member.gid != 0: raise RuntimeError('updater_install: %s: invalid uid/gid' % member.name)
def walk_generic(self, test, index): """ Walk over the results of a generic test """ filename = "%s.pickle" % test if index != None: filename += "." + str(int(index)) fullpath = utils_path.append(self.proxy.datadir, filename, False) if not fullpath: return [] if not os.path.isfile(fullpath): return [] filep = open(fullpath, "rb") content = filep.read() filep.close() if not content: return [] return pickle.loads(content)
def tarball_path(basedir, vinfo): ''' Return tarball path ''' name = '.'.join([vinfo, 'tar', 'gz']) path = utils_path.append(basedir, name) return path
def process_request(self, stream, request): ''' Process a request and generate the response ''' response = Message() if not request.uri.startswith("/"): response.compose(code="403", reason="Forbidden", body="403 Forbidden") stream.send_response(request, response) return for prefix, child in self.childs.items(): if request.uri.startswith(prefix): child.process_request(stream, request) return rootdir = self.conf.get("http.server.rootdir", "") if not rootdir: response.compose(code="403", reason="Forbidden", body="403 Forbidden") stream.send_response(request, response) return if request.uri == "/": response.compose_redirect(stream, "/api/index") stream.send_response(request, response) return if '?' in request.uri: request_uri = request.uri.split('?')[0] else: request_uri = request.uri fullpath = utils_path.append(rootdir, request_uri, True) if not fullpath: response.compose(code="403", reason="Forbidden", body="403 Forbidden") stream.send_response(request, response) return try: filep = open(fullpath, "rb") except (IOError, OSError): logging.error("HTTP: Not Found: %s (WWWDIR: %s)", fullpath, rootdir) response.compose(code="404", reason="Not Found", body="404 Not Found") stream.send_response(request, response) return if self.conf.get("http.server.mime", True): mimetype, encoding = mimetypes.guess_type(fullpath) # Do not attempt SSI if the resource is, say, gzipped if not encoding: if mimetype == "text/html": ssi = self.conf.get("http.server.ssi", False) if ssi: body = ssi_replace(rootdir, filep) filep = StringIO.StringIO(body) #XXX Do we need to enforce the charset? if mimetype in ("text/html", "application/x-javascript"): mimetype += "; charset=UTF-8" else: response["content-encoding"] = encoding else: mimetype = "text/plain" response.compose(code="200", reason="Ok", body=filep, mimetype=mimetype) if request.method == "HEAD": utils.safe_seek(filep, 0, os.SEEK_END) stream.send_response(request, response)
def ssi_open(rootdir, path, mode): ''' Wrapper for open() that makes security checks ''' path = utils_path.append(rootdir, path, False) if not path: raise ValueError("ssi: Path name above root directory") return open(path, mode)
import cgi import os from neubot.compat import json from neubot.config import CONFIG from neubot.http.message import Message from neubot.utils_api import NotImplementedTest from neubot import utils_hier from neubot import utils_path from neubot import utils # Directory that contains the description of each test, which consists of # two files per test: a JSON file and an HTML file. TESTDIR = utils_path.append(utils_hier.WWWDIR, "test") # Config variables to be copied to output: they allow ordinary users to # configure the appearance of results.html. COPY_CONFIG_VARIABLES = ( "www_no_description", "www_no_legend", "www_no_plot", "www_no_split_by_ip", "www_no_table", "www_no_title", ) def api_results(stream, request, query): """ Populates www/results.html page """
def test__5(self): ''' Test append() squeezes after-join() multiple slashes ''' self.assertEqual(utils_path.append('/foo', '/bar'), '/foo/bar')
def signature_path(basedir, vinfo): ''' Return signature path ''' name = '.'.join([vinfo, 'tar', 'gz', 'sig']) path = utils_path.append(basedir, name) return path