python icon indicating copy to clipboard operation
python copied to clipboard

`Database` constructor fails with unix sockets

Open jtracey opened this issue 2 years ago • 1 comments

When trying to launch maubot, I get the following exception: raise ValueError("Invalid URL: host is required for absolute urls")

This originates from yarl, called via mautrix's Database constructor: https://github.com/mautrix/python/blob/735d0c139e48777cbd2385ed15fdb549113914c4/mautrix/util/async_db/database.py#L66

If you consult Postgres' documentation, you'll see in that the netloc portion of the URI is optional:

postgresql://[user[:password]@][netloc][:port][/dbname][?param1=value1&...]

In fact, not only is it optional, omitting it is the only way to indicate connection to a Unix socket:

In particular, a Unix-domain socket connection is chosen if the host part is either empty or starts with a slash, otherwise a TCP/IP connection is initiated.

This is fairly important for security purposes, as Unix sockets are the standard way to ensure a local database can never be remotely accessed. I don't think urllib has this problem, and the check is fairly minimal and explicit, so I suspect it's a design decision on yarl's part to parse URLs, not arbitrary URIs.

For now, users can be work around this by explicitly encoding the default Unix socket path, using percent escapes to avoid yarl parsing the path as the URI hierarchy, e.g.: postgresql://username:secret@%2Fvar%2Frun%2Fpostgresql/dbname, but this really should be fixed.

jtracey avatar Sep 01 '22 07:09 jtracey

The usual way is postgres:///dbname, but escaped host or using the ?host parameter work too, so there isn't really any reason to fix this.

tulir avatar Sep 01 '22 13:09 tulir

this does not work either:

postgresql://matrix:matrix@/telegram?host=/var/snap/matrix/current/database&port=5436

error:

ValueError: Invalid URL: host is required for absolute urls

cyberb avatar Nov 23 '23 18:11 cyberb

That's the same as in the original issue. URL-encoded host in the netloc field or specifying user/password via query params works

tulir avatar Nov 23 '23 19:11 tulir

this still does not work:

postgresql://matrix:password-redacted@%2Fvar%2Fsnap%2Fmatrix%2Fcurrent%2Fdatabase/telegram?port=5436

produces:

Traceback (most recent call last):
  File "/snap/matrix/x2/python/usr/local/lib/python3.8/site-packages/mautrix/bridge/bridge.py", line 215, in start_db
    await self.db.start()
  File "/snap/matrix/x2/python/usr/local/lib/python3.8/site-packages/mautrix/util/async_db/asyncpg.py", line 71, in start
    self._pool = await asyncpg.create_pool(str(self.url), **self._db_args)
  File "/snap/matrix/x2/python/usr/local/lib/python3.8/site-packages/asyncpg/pool.py", line 409, in _async__init__
    await self._initialize()
  File "/snap/matrix/x2/python/usr/local/lib/python3.8/site-packages/asyncpg/pool.py", line 437, in _initialize
    await first_ch.connect()
  File "/snap/matrix/x2/python/usr/local/lib/python3.8/site-packages/asyncpg/pool.py", line 129, in connect
    self._con = await self._pool._get_new_connection()
  File "/snap/matrix/x2/python/usr/local/lib/python3.8/site-packages/asyncpg/pool.py", line 507, in _get_new_connection
    con = await connection.connect(
  File "/snap/matrix/x2/python/usr/local/lib/python3.8/site-packages/asyncpg/connection.py", line 2092, in connect
    return await connect_utils._connect(
  File "/snap/matrix/x2/python/usr/local/lib/python3.8/site-packages/asyncpg/connect_utils.py", line 895, in _connect
    raise last_error
  File "/snap/matrix/x2/python/usr/local/lib/python3.8/site-packages/asyncpg/connect_utils.py", line 881, in _connect
    return await _connect_addr(
  File "/snap/matrix/x2/python/usr/local/lib/python3.8/site-packages/asyncpg/connect_utils.py", line 768, in _connect_addr
    return await __connect_addr(params, timeout, False, *args)
  File "/snap/matrix/x2/python/usr/local/lib/python3.8/site-packages/asyncpg/connect_utils.py", line 825, in __connect_addr
    tr, pr = await compat.wait_for(connector, timeout=timeout)
  File "/snap/matrix/x2/python/usr/local/lib/python3.8/site-packages/asyncpg/compat.py", line 56, in wait_for
    return await asyncio.wait_for(fut, timeout)
  File "/snap/matrix/x2/python/usr/local/lib/python3.8/asyncio/tasks.py", line 494, in wait_for
    return fut.result()
  File "/snap/matrix/x2/python/usr/local/lib/python3.8/asyncio/unix_events.py", line 244, in create_unix_connection
    await self.sock_connect(sock, path)
  File "/snap/matrix/x2/python/usr/local/lib/python3.8/asyncio/selector_events.py", line 496, in sock_connect
    return await fut
  File "/snap/matrix/x2/python/usr/local/lib/python3.8/asyncio/selector_events.py", line 501, in _sock_connect
    sock.connect(address)
FileNotFoundError: [Errno 2] No such file or directory

while this is ok:

postgresql:///telegram?host=/var/snap/matrix/current/database&user=matrix&password=matrix&port=5436

cyberb avatar Nov 23 '23 21:11 cyberb