Repository: edgedb/edgedb

Issue:
[Feature] Expose the generate_uuid_v4() function from the uuid-ossp Postgres extension
OWASP suggests session keys contain **at least 128 bits** of random information. The ideal data type that is fixed-size and also optimised for fast lookup by Postgres is the UUID type, which also happens to be exactly 128 bits.

The EdgeDB standard library only exposes `uuid_generate_v1mc()` from the `uuid-ossp` Postgres extension. While this is sufficient for primary keys, UUID v1 should **never be used for any sort of authorization purpose**, the randomised MAC address accounts for only 48 bits. Given a previous key, it becomes _much_ easier to predict future keys ([UUID version differences](https://versprite.com/blog/universally-unique-identifiers/)).

See the below example for UUIDs generating using `uuid_generate_v1mc()` in quick succession:

```text
{91b24894-c0cb-11ec-b79f-cf8b1d655c91}
{91e0c44e-c0cb-11ec-b79f-9bd023a1c068}
{920794de-c0cb-11ec-b79f-af1198448bf5}
{92365404-c0cb-11ec-b79f-5b4335fd24ab}
{92695fd4-c0cb-11ec-b79f-676e47860109}
{9296a430-c0cb-11ec-b79f-175ed269c4b4}
```

Postgres exposes a `uuid_generate_v4()` function in the exactly the same extension as `uuid_generate_v1mc()` (`uuid-ossp`). UUID v4 possesses 122 bits of purely random information, which is acceptable for most applications that aren't particularly sensitive.

The stored v4 UUID could also be combined with the primary key UUID of the object to give 170 bits of random information, whilst being optimised for lookup and storage efficiency.

I've escalated this from a Discord reply:

> Yeah, exposing built-in Postgres functions is trivial.  Please open an issue

Would such a feature be implementable? The current solution is to generate the UUID v4 on the server before insertion, Node.js supports this natively via the `crypto.randomUUID()` function, but not a lot of people know this and rely instead on more third-party packages.


Discussion:

Resolving patch:
diff --git a/edb/buildmeta.py b/edb/buildmeta.py
--- a/edb/buildmeta.py
+++ b/edb/buildmeta.py
@@ -44,7 +44,7 @@
 
 
 # Increment this whenever the database layout or stdlib changes.
-EDGEDB_CATALOG_VERSION = 2022_04_15_00_01
+EDGEDB_CATALOG_VERSION = 2022_04_20_00_01
 EDGEDB_MAJOR_VERSION = 2
 
 


Test patch:
diff --git a/tests/test_edgeql_casts.py b/tests/test_edgeql_casts.py
--- a/tests/test_edgeql_casts.py
+++ b/tests/test_edgeql_casts.py
@@ -320,7 +320,7 @@ async def test_edgeql_casts_idempotence_02(self):
 
         await self.assert_query_result(
             r'''
-                WITH U := uuid_generate_v1mc()
+                WITH U := uuid_generate_v4()
                 SELECT <uuid><uuid>U = U;
             ''',
             [True],
diff --git a/tests/test_edgeql_volatility.py b/tests/test_edgeql_volatility.py
--- a/tests/test_edgeql_volatility.py
+++ b/tests/test_edgeql_volatility.py
@@ -210,7 +210,7 @@ async def test_edgeql_volatility_for_01(self):
         await self.assert_query_result(
             r'''
                 SELECT count(DISTINCT (FOR x in {1,2} UNION (
-                    uuid_generate_v1mc())));
+                    uuid_generate_v4())));
             ''',
             [2],
         )
@@ -270,7 +270,7 @@ async def test_edgeql_volatility_for_07(self):
         await self.assert_query_result(
             r'''
                 SELECT count(DISTINCT (FOR x in {(),()} UNION (
-                    uuid_generate_v1mc())));
+                    uuid_generate_v4())));
             ''',
             [2],
         )