def test_connection_info(): url = "postgres://*****:*****@dbhost.local:5555/abc?replication=true&sslmode=foobar&sslmode=require" cs = "host=dbhost.local user='******' dbname='abc'\n" \ "replication=true password=secret sslmode=require port=5555" ci = { "host": "dbhost.local", "port": "5555", "user": "******", "password": "******", "dbname": "abc", "replication": "true", "sslmode": "require", } assert get_connection_info(ci) == get_connection_info(cs) assert get_connection_info(ci) == get_connection_info(url) basic_cstr = "host=localhost user=os" assert create_connection_string(get_connection_info(basic_cstr)) == "host='localhost' user='******'" assert get_connection_info("foo=bar bar='\\'x'") == {"foo": "bar", "bar": "'x"} with raises(ValueError): get_connection_info("foo=bar x") with raises(ValueError): get_connection_info("foo=bar bar='x")
def test_connection_info(): url = "postgres://*****:*****@dbhost.local:5555/abc?replication=true&sslmode=foobar&sslmode=require" cs = "host=dbhost.local user='******' dbname='abc'\n" \ "replication=true password=secret sslmode=require port=5555" ci = { "host": "dbhost.local", "port": "5555", "user": "******", "password": "******", "dbname": "abc", "replication": "true", "sslmode": "require", } assert get_connection_info(ci) == get_connection_info(cs) assert get_connection_info(ci) == get_connection_info(url) basic_cstr = "host=localhost user=os" assert create_connection_string( get_connection_info(basic_cstr)) == "host='localhost' user='******'" assert get_connection_info("foo=bar bar='\\'x'") == { "foo": "bar", "bar": "'x" } with raises(ValueError): get_connection_info("foo=bar x") with raises(ValueError): get_connection_info("foo=bar bar='x")
def create_pgpass_file(connection_string_or_info): """Look up password from the given object which can be a dict or a string and write a possible password in a pgpass file; returns a connection_string without a password in it""" info = pgutil.get_connection_info(connection_string_or_info) if "password" not in info: return pgutil.create_connection_string(info) linekey = "{host}:{port}:{dbname}:{user}:".format( host=info.get("host", "localhost"), port=info.get("port", 5432), user=info.get("user", ""), dbname=info.get("dbname", "*")) pwline = "{linekey}{password}".format(linekey=linekey, password=info.pop("password")) pgpass_path = os.path.join(os.environ.get("HOME"), ".pgpass") if os.path.exists(pgpass_path): with open(pgpass_path, "r") as fp: pgpass_lines = fp.read().splitlines() else: pgpass_lines = [] if pwline in pgpass_lines: LOG.debug( "Not adding authentication data to: %s since it's already there", pgpass_path) else: # filter out any existing lines with our linekey and add the new line pgpass_lines = [ line for line in pgpass_lines if not line.startswith(linekey) ] + [pwline] content = "\n".join(pgpass_lines) + "\n" with open(pgpass_path, "w") as fp: os.fchmod(fp.fileno(), 0o600) fp.write(content) LOG.debug("Wrote %r to %r", pwline, pgpass_path) return pgutil.create_connection_string(info)
def create_pgpass_file(connection_string_or_info): """Look up password from the given object which can be a dict or a string and write a possible password in a pgpass file; returns a connection_string without a password in it""" info = pgutil.get_connection_info(connection_string_or_info) if "password" not in info: return pgutil.create_connection_string(info) linekey = "{host}:{port}:{dbname}:{user}:".format( host=info.get("host", "localhost"), port=info.get("port", 5432), user=info.get("user", ""), dbname=info.get("dbname", "*")) pwline = "{linekey}{password}".format(linekey=linekey, password=info.pop("password")) pgpass_path = os.path.join(os.environ.get("HOME"), ".pgpass") if os.path.exists(pgpass_path): with open(pgpass_path, "r") as fp: pgpass_lines = fp.read().splitlines() else: pgpass_lines = [] if pwline in pgpass_lines: LOG.debug("Not adding authentication data to: %s since it's already there", pgpass_path) else: # filter out any existing lines with our linekey and add the new line pgpass_lines = [line for line in pgpass_lines if not line.startswith(linekey)] + [pwline] content = "\n".join(pgpass_lines) + "\n" with open(pgpass_path, "w") as fp: os.fchmod(fp.fileno(), 0o600) fp.write(content) LOG.debug("Wrote %r to %r", pwline, pgpass_path) return pgutil.create_connection_string(info)
def connection_info_and_slot(target_node_info): """Process the input `target_node_info` entry which may be a libpq connection string or uri, or a dict containing key:value pairs of connection info entries or just the connection string with a replication slot name. Return the connection info dict and a possible slot.""" slot = None if isinstance(target_node_info, dict): target_node_info = target_node_info.copy() slot = target_node_info.pop("slot", None) if list(target_node_info) == ["connection_string"]: # if the dict only contains the `connection_string` key use it as-is target_node_info = target_node_info["connection_string"] connection_info = pgutil.get_connection_info(target_node_info) return connection_info, slot
def test_mask_connection_info(): url = "postgres://*****:*****@dbhost.local:5555/abc?replication=true&sslmode=foobar&sslmode=require" cs = "host=dbhost.local user='******' dbname='abc'\n" \ "replication=true password=secret sslmode=require port=5555" ci = get_connection_info(cs) masked_url = mask_connection_info(url) masked_cs = mask_connection_info(url) masked_ci = mask_connection_info(url) assert masked_url == masked_cs assert masked_url == masked_ci assert "password" in ci # make sure we didn't modify the original dict # the return format is a connection string without password, followed by # a semicolon and comment about password presence masked_str, password_info = masked_url.split("; ", 1) assert "password" not in masked_str assert password_info == "hidden password" # remasking the masked string should yield a no password comment masked_masked = mask_connection_info(masked_str) _, masked_password_info = masked_masked.split("; ", 1) assert masked_password_info == "no password"