mirror of
https://github.com/maxkratz/edgedb.git
synced 2024-09-16 18:59:05 +00:00
Get rid of deterministic collection id generation (#4463)
It is a weird mismatch with the rest of the system, and introduces scope for weird collision attacks if untrusted users to a system can control explicitly inserted ids. Co-authored-by: Elvis Pranskevichus <elvis@edgedb.com>
This commit is contained in:
parent
b711207bc4
commit
b0a9f230dd
7 changed files with 36 additions and 138 deletions
|
@ -44,7 +44,7 @@ from edb.common import verutils
|
|||
|
||||
|
||||
# Increment this whenever the database layout or stdlib changes.
|
||||
EDGEDB_CATALOG_VERSION = 2022_10_07_00_00
|
||||
EDGEDB_CATALOG_VERSION = 2022_10_11_00_00
|
||||
EDGEDB_MAJOR_VERSION = 3
|
||||
|
||||
|
||||
|
|
|
@ -589,7 +589,9 @@ def compile_TypeCast(
|
|||
)
|
||||
|
||||
if ex_param := ctx.env.script_params.get(param_name):
|
||||
param_first_type = ex_param.schema_type
|
||||
# N.B. Accessing the schema_type from the param is unreliable
|
||||
ctx.env.schema, param_first_type = irtyputils.ir_typeref_to_type(
|
||||
ctx.env.schema, ex_param.ir_type)
|
||||
if param_first_type != pt:
|
||||
raise errors.QueryError(
|
||||
f'parameter type '
|
||||
|
|
|
@ -3981,17 +3981,7 @@ class GetBaseScalarTypeMap(dbops.Function):
|
|||
else ql(f'pg_catalog.{v[0]}')
|
||||
}
|
||||
)"""
|
||||
for k, v in types.base_type_name_map.items())},
|
||||
|
||||
{", ".join(
|
||||
f"""(
|
||||
{ql(str(k))}::uuid,
|
||||
{
|
||||
ql(f'{v[0]}.{v[1]}') if len(v) == 2
|
||||
else ql(f'pg_catalog.{v[0]}')
|
||||
}
|
||||
)"""
|
||||
for k, v in types.base_range_name_map.items())}
|
||||
for k, v in types.base_type_name_map.items())}
|
||||
'''
|
||||
|
||||
def __init__(self) -> None:
|
||||
|
@ -4044,7 +4034,27 @@ class GetPgTypeForEdgeDBTypeFunction(dbops.Function):
|
|||
edgedb._get_base_scalar_type_map()
|
||||
AS m(tid uuid, tn text)
|
||||
WHERE
|
||||
tid = elemid
|
||||
tid = "elemid"
|
||||
)
|
||||
),
|
||||
(
|
||||
SELECT
|
||||
rng.rngtypid
|
||||
FROM
|
||||
pg_catalog.pg_range rng
|
||||
INNER JOIN pg_catalog.pg_type typ
|
||||
ON (rng.rngsubtype = typ.oid)
|
||||
WHERE
|
||||
typ.typname = "elemid"::text || '_domain'
|
||||
OR typ.typname = "elemid"::text || '_t'
|
||||
OR typ.oid = (
|
||||
SELECT
|
||||
tn::regtype::oid
|
||||
FROM
|
||||
edgedb._get_base_scalar_type_map()
|
||||
AS m(tid uuid, tn text)
|
||||
WHERE
|
||||
tid = "elemid"
|
||||
)
|
||||
),
|
||||
edgedb.raise(
|
||||
|
@ -4053,7 +4063,7 @@ class GetPgTypeForEdgeDBTypeFunction(dbops.Function):
|
|||
msg => (
|
||||
format(
|
||||
'cannot determine OID of EdgeDB type %L',
|
||||
typeid::text
|
||||
"typeid"::text
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -33,7 +33,6 @@ from edb.schema import objtypes as s_objtypes
|
|||
from edb.schema import name as sn
|
||||
from edb.schema import objects as s_obj
|
||||
from edb.schema import schema as s_schema
|
||||
from edb.schema import types as s_types
|
||||
|
||||
from . import common
|
||||
|
||||
|
@ -122,17 +121,6 @@ base_type_name_map_r = {
|
|||
'memory_t': sn.QualName('cfg', 'memory'),
|
||||
}
|
||||
|
||||
# Use the known type IDs to generate corresponding range type IDs
|
||||
base_range_name_map = {
|
||||
s_types.generate_type_id(
|
||||
f'''range-{
|
||||
s_obj.get_known_type_id(
|
||||
base_type_name_map_r[".".join(pg_type)])
|
||||
}'''
|
||||
): pg_range
|
||||
for pg_type, pg_range in type_to_range_name_map.items()
|
||||
}
|
||||
|
||||
|
||||
def is_builtin_scalar(schema, scalar):
|
||||
return scalar.id in base_type_name_map
|
||||
|
|
|
@ -424,7 +424,7 @@ def _build_object_mutation_shape(
|
|||
and not issubclass(mcls, s_types.CollectionExprAlias)
|
||||
and not cmd.get_attribute_value('abstract')
|
||||
):
|
||||
if issubclass(mcls, s_types.Array):
|
||||
if issubclass(mcls, (s_types.Array, s_types.Range)):
|
||||
assignments.append(
|
||||
f'backend_id := sys::_get_pg_type_for_edgedb_type('
|
||||
f'<uuid>$__{var_prefix}id, '
|
||||
|
|
|
@ -1093,9 +1093,6 @@ class CollectionTypeShell(TypeShell[CollectionTypeT_co]):
|
|||
) -> typing.Tuple[TypeShell[Type], ...]:
|
||||
raise NotImplementedError
|
||||
|
||||
def get_id(self, schema: s_schema.Schema) -> uuid.UUID:
|
||||
raise NotImplementedError
|
||||
|
||||
def is_polymorphic(self, schema: s_schema.Schema) -> bool:
|
||||
return any(
|
||||
st.is_polymorphic(schema) for st in self.get_subtypes(schema)
|
||||
|
@ -1157,24 +1154,6 @@ class Array(
|
|||
compcoef=0,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def generate_id(
|
||||
cls,
|
||||
schema: s_schema.Schema,
|
||||
data: Dict[str, Any],
|
||||
) -> uuid.UUID:
|
||||
if (
|
||||
data.get('alias_is_persistent')
|
||||
or isinstance(data.get('name'), s_name.QualName)
|
||||
):
|
||||
return super().generate_id(schema, data)
|
||||
else:
|
||||
return generate_array_type_id(
|
||||
schema,
|
||||
data['element_type'],
|
||||
data['dimensions'],
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def generate_name(
|
||||
cls,
|
||||
|
@ -1219,6 +1198,8 @@ class Array(
|
|||
dimensions=dimensions,
|
||||
**kwargs,
|
||||
)
|
||||
# Compute material type so that we can retrieve it safely later
|
||||
schema, _ = result.material_type(schema)
|
||||
|
||||
return schema, result
|
||||
|
||||
|
@ -1471,14 +1452,11 @@ class ArrayTypeShell(CollectionTypeShell[Array_T_co]):
|
|||
def get_displayname(self, schema: s_schema.Schema) -> str:
|
||||
return f'array<{self.subtype.get_displayname(schema)}>'
|
||||
|
||||
def get_id(self, schema: s_schema.Schema) -> uuid.UUID:
|
||||
return generate_array_type_id(schema, self.subtype, self.typemods[0])
|
||||
|
||||
def resolve(self, schema: s_schema.Schema) -> Array_T_co:
|
||||
if isinstance(self.name, s_name.QualName):
|
||||
arr = schema.get(self.name, type=Array)
|
||||
else:
|
||||
arr = schema.get_by_id(self.get_id(schema), type=Array)
|
||||
arr = schema.get_global(Array, self.get_name(schema))
|
||||
return arr # type: ignore
|
||||
|
||||
def as_create_delta(
|
||||
|
@ -1495,7 +1473,6 @@ class ArrayTypeShell(CollectionTypeShell[Array_T_co]):
|
|||
classname=self.get_name(schema),
|
||||
if_not_exists=True,
|
||||
)
|
||||
ca.set_attribute_value('id', self.get_id(schema))
|
||||
else:
|
||||
ca = CreateArrayExprAlias(
|
||||
classname=view_name,
|
||||
|
@ -1561,21 +1538,6 @@ class Tuple(
|
|||
reflection_proxy=('schema::TupleElement', 'type'),
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def generate_id(
|
||||
cls,
|
||||
schema: s_schema.Schema,
|
||||
data: Dict[str, Any],
|
||||
) -> uuid.UUID:
|
||||
if isinstance(data['name'], s_name.QualName):
|
||||
return super().generate_id(schema, data)
|
||||
else:
|
||||
return generate_tuple_type_id(
|
||||
schema,
|
||||
dict(data['element_types'].items(schema)),
|
||||
data.get('named', False),
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def generate_name(
|
||||
cls,
|
||||
|
@ -1623,6 +1585,8 @@ class Tuple(
|
|||
element_types=el_types,
|
||||
**kwargs,
|
||||
)
|
||||
# Compute material type so that we can retrieve it safely later
|
||||
schema, _ = result.material_type(schema)
|
||||
|
||||
return schema, result
|
||||
|
||||
|
@ -2053,14 +2017,11 @@ class TupleTypeShell(CollectionTypeShell[Tuple_T_co]):
|
|||
def is_named(self) -> bool:
|
||||
return self.typemods is not None and self.typemods.get('named', False)
|
||||
|
||||
def get_id(self, schema: s_schema.Schema) -> uuid.UUID:
|
||||
return generate_tuple_type_id(schema, self.subtypes, self.is_named())
|
||||
|
||||
def resolve(self, schema: s_schema.Schema) -> Tuple_T_co:
|
||||
if isinstance(self.name, s_name.QualName):
|
||||
tup = schema.get(self.name, type=Tuple)
|
||||
else:
|
||||
tup = schema.get_by_id(self.get_id(schema), type=Tuple)
|
||||
tup = schema.get_global(Tuple, self.get_name(schema))
|
||||
return tup # type: ignore
|
||||
|
||||
def as_create_delta(
|
||||
|
@ -2097,7 +2058,6 @@ class TupleTypeShell(CollectionTypeShell[Tuple_T_co]):
|
|||
self.is_named(),
|
||||
)
|
||||
ct = CreateTuple(classname=name, if_not_exists=True)
|
||||
ct.set_attribute_value('id', self.get_id(schema))
|
||||
self._populate_create_delta(schema, ct)
|
||||
return ct
|
||||
|
||||
|
@ -2150,23 +2110,6 @@ class Range(
|
|||
compcoef=0,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def generate_id(
|
||||
cls,
|
||||
schema: s_schema.Schema,
|
||||
data: Dict[str, Any],
|
||||
) -> uuid.UUID:
|
||||
if (
|
||||
data.get('alias_is_persistent')
|
||||
or isinstance(data.get('name'), s_name.QualName)
|
||||
):
|
||||
return super().generate_id(schema, data)
|
||||
else:
|
||||
return generate_range_type_id(
|
||||
schema,
|
||||
data['element_type'],
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def generate_name(
|
||||
cls,
|
||||
|
@ -2436,14 +2379,11 @@ class RangeTypeShell(CollectionTypeShell[Range_T_co]):
|
|||
def get_displayname(self, schema: s_schema.Schema) -> str:
|
||||
return f'range<{self.subtype.get_displayname(schema)}>'
|
||||
|
||||
def get_id(self, schema: s_schema.Schema) -> uuid.UUID:
|
||||
return generate_range_type_id(schema, self.subtype)
|
||||
|
||||
def resolve(self, schema: s_schema.Schema) -> Range_T_co:
|
||||
if isinstance(self.name, s_name.QualName):
|
||||
rng = schema.get(self.name, type=Range)
|
||||
else:
|
||||
rng = schema.get_by_id(self.get_id(schema), type=Range)
|
||||
rng = schema.get_global(Range, self.get_name(schema))
|
||||
return rng # type: ignore
|
||||
|
||||
def as_create_delta(
|
||||
|
@ -2460,7 +2400,6 @@ class RangeTypeShell(CollectionTypeShell[Range_T_co]):
|
|||
classname=self.get_name(schema),
|
||||
if_not_exists=True,
|
||||
)
|
||||
ca.set_attribute_value('id', self.get_id(schema))
|
||||
else:
|
||||
ca = CreateRangeExprAlias(
|
||||
classname=view_name,
|
||||
|
@ -2497,47 +2436,6 @@ class RangeExprAlias(
|
|||
return Range
|
||||
|
||||
|
||||
def generate_type_id(id_str: str) -> uuid.UUID:
|
||||
return uuidgen.uuid5(TYPE_ID_NAMESPACE, id_str)
|
||||
|
||||
|
||||
def generate_tuple_type_id(
|
||||
schema: s_schema.Schema,
|
||||
element_types: Mapping[str, Union[Type, TypeShell[Type]]],
|
||||
named: bool = False,
|
||||
*quals: str,
|
||||
) -> uuid.UUID:
|
||||
id_str = ','.join(
|
||||
f'{n}:{st.get_id(schema)}' for n, st in element_types.items())
|
||||
id_str = f'{"named" if named else ""}tuple-{id_str}'
|
||||
if quals:
|
||||
id_str = f'{id_str}_{"-".join(quals)}'
|
||||
return generate_type_id(id_str)
|
||||
|
||||
|
||||
def generate_array_type_id(
|
||||
schema: s_schema.Schema,
|
||||
element_type: Union[Type, TypeShell[Type]],
|
||||
dimensions: Sequence[int] = (),
|
||||
*quals: str,
|
||||
) -> uuid.UUID:
|
||||
id_basis = f'array-{element_type.get_id(schema)}-{dimensions}'
|
||||
if quals:
|
||||
id_basis = f'{id_basis}-{"-".join(quals)}'
|
||||
return generate_type_id(id_basis)
|
||||
|
||||
|
||||
def generate_range_type_id(
|
||||
schema: s_schema.Schema,
|
||||
element_type: Union[Type, TypeShell[Type]],
|
||||
*quals: str,
|
||||
) -> uuid.UUID:
|
||||
id_basis = f'range-{element_type.get_id(schema)}'
|
||||
if quals:
|
||||
id_basis = f'{id_basis}-{"-".join(quals)}'
|
||||
return generate_type_id(id_basis)
|
||||
|
||||
|
||||
def get_union_type_name(
|
||||
component_names: typing.Iterable[s_name.Name],
|
||||
*,
|
||||
|
|
|
@ -1050,7 +1050,7 @@ async def _init_stdlib(
|
|||
compiler,
|
||||
stdlib.reflschema,
|
||||
'''
|
||||
UPDATE schema::Array
|
||||
UPDATE (schema::Array UNION schema::Range)
|
||||
FILTER
|
||||
.builtin
|
||||
AND NOT (.abstract ?? False)
|
||||
|
|
Loading…
Reference in a new issue