示例#1
0
    async def list_versions(
        self, organization_id: OrganizationID, author: DeviceID, vlob_id: UUID
    ) -> Dict[int, Tuple[pendulum.Pendulum, DeviceID]]:

        async with self.dbh.pool.acquire() as conn:
            async with conn.transaction():

                realm_id = await _get_realm_id_from_vlob_id(conn, organization_id, vlob_id)
                await _check_realm_and_read_access(conn, organization_id, author, realm_id, None)

                query = """
SELECT
    version,
    ({}) as author,
    created_on
FROM vlob_atom
WHERE
    organization = ({})
    AND vlob_id = $2
ORDER BY version DESC
""".format(
                    q_device(_id=Parameter("author")).select("device_id"),
                    q_organization_internal_id(Parameter("$1")),
                )
                rows = await conn.fetch(query, organization_id, vlob_id)
                assert rows
        if not rows:
            raise VlobNotFoundError(f"Vlob `{vlob_id}` doesn't exist")

        return {row["version"]: (row["created_on"], row["author"]) for row in rows}
示例#2
0
def _q_factory(query, omit_revoked):
    _param_count = itertools.count(1)

    def _next_param():
        return Parameter(f"${next(_param_count)}")

    q = (Query.from_(t_user).select(t_user.user_id).where(
        (t_user.organization == q_organization_internal_id(
            _next_param()))).orderby(t_user.user_id))
    if query:
        q = q.where(IRegex(t_user.user_id, _next_param()))
    if omit_revoked:
        q = q.where(
            t_user.revoked_on.isnull() | t_user.revoked_on > _next_param())
    return q
示例#3
0
    async def group_check(
        self, organization_id: OrganizationID, author: DeviceID, to_check: List[dict]
    ) -> List[dict]:
        changed = []
        to_check_dict = {}
        for x in to_check:
            if x["version"] == 0:
                changed.append({"vlob_id": x["vlob_id"], "version": 0})
            else:
                to_check_dict[x["vlob_id"]] = x

        async with self.dbh.pool.acquire() as conn:
            query = """
SELECT DISTINCT ON (vlob_id) vlob_id, version
FROM vlob_atom
WHERE
    organization = ({})
    AND vlob_id = any($3::uuid[])
    AND ({})
    AND NOT ({})
ORDER BY vlob_id, version DESC
""".format(
                q_organization_internal_id(Parameter("$1")),
                q_user_can_read_vlob(
                    organization_id=Parameter("$1"),
                    user_id=Parameter("$2"),
                    realm=Query.from_(t_vlob_encryption_revision)
                    .select("realm")
                    .where(t_vlob_encryption_revision._id == Parameter("vlob_encryption_revision")),
                ),
                q_realm_in_maintenance(
                    realm=Query.from_(t_vlob_encryption_revision)
                    .select("realm")
                    .where(t_vlob_encryption_revision._id == Parameter("vlob_encryption_revision"))
                ),
            )

            rows = await conn.fetch(query, organization_id, author.user_id, to_check_dict.keys())

        for vlob_id, version in rows:
            if version != to_check_dict[vlob_id]["version"]:
                changed.append({"vlob_id": vlob_id, "version": version})

        return changed
示例#4
0
def _q_human_factory(query, omit_revoked, omit_non_human):
    _param_count = itertools.count(1)

    def _next_param():
        return Parameter(f"${next(_param_count)}")

    q_revoked = t_user.revoked_on.notnull() & (t_user.revoked_on <=
                                               _next_param())
    q = (Query.from_(t_user).left_join(t_human).on(
        t_user.human == t_human._id).select(
            t_user.user_id, t_human.email, t_human.label,
            q_revoked.as_("revoked")).where(
                (t_user.organization == q_organization_internal_id(
                    _next_param()))))
    if query:
        q = q.where(
            IRegex(Concat(t_human.label, t_human.email, t_user.user_id),
                   _next_param()))
    if omit_revoked:
        q = q.where(q_revoked.negate())
    if omit_non_human:
        q = q.where(t_user.human.notnull())

    return q.get_sql()
示例#5
0
from parsec.backend.postgresql.tables import (
    t_device,
    t_user,
    q_organization_internal_id,
    q_user_internal_id,
    q_device_internal_id,
)

_q_get_user_devices = (Query.from_(t_device).select(
    t_device.device_id).where(t_device.user_ == q_user_internal_id(
        organization_id=Parameter("$1"), user_id=Parameter("$2"))).get_sql())

_q_insert_user = (Query.into(t_user).columns(
    "organization", "user_id", "is_admin", "user_certificate",
    "user_certifier", "created_on").insert(
        q_organization_internal_id(Parameter("$1")),
        Parameter("$2"),
        Parameter("$3"),
        Parameter("$4"),
        q_device_internal_id(organization_id=Parameter("$1"),
                             device_id=Parameter("$5")),
        Parameter("$6"),
    ).get_sql())

_q_insert_device = (Query.into(t_device).columns(
    "organization", "user_", "device_id", "device_certificate",
    "device_certifier", "created_on").insert(
        q_organization_internal_id(Parameter("$1")),
        q_user_internal_id(organization_id=Parameter("$1"),
                           user_id=Parameter("$2")),
        Parameter("$3"),
示例#6
0
    q_device_internal_id,
)

_q_insert_realm = """
INSERT INTO realm (
    organization,
    realm_id,
    encryption_revision
) SELECT
    ({}),
    ({}),
    1
ON CONFLICT (organization, realm_id) DO NOTHING
RETURNING
_id
""".format(q_organization_internal_id(Parameter("$1")), Parameter("$2"))

_q_insert_realm_role = """
INSERT INTO realm_user_role(
    realm,
    user_,
    role,
    certificate,
    certified_by,
    certified_on
)
SELECT
    ({}), ({}), ({}), ({}), ({}), ({})
""".format(
    Parameter("$1"),
    q_user_internal_id(organization_id=Parameter("$2"),
示例#7
0
    q_organization_internal_id,
    q_user_internal_id,
)

_q_get_user = (Query.from_(t_user).select(
    "profile",
    "user_certificate",
    "redacted_user_certificate",
    q_device(_id=t_user.user_certifier).select(
        t_device.device_id).as_("user_certifier"),
    "created_on",
    "revoked_on",
    "revoked_user_certificate",
    q_device(_id=t_user.revoked_user_certifier).select(
        t_device.device_id).as_("revoked_user_certifier"),
).where((t_user.organization == q_organization_internal_id(Parameter("$1")))
        & (t_user.user_id == Parameter("$2"))).get_sql())

_t_d1 = t_device.as_("d1")
_t_d2 = t_device.as_("d2")
_t_d3 = t_device.as_("d3")

_q_get_device = (Query.from_(_t_d1).select(
    "device_label",
    "device_certificate",
    "redacted_device_certificate",
    q_device(_id=_t_d1.device_certifier,
             table=_t_d2).select(_t_d2.device_id).as_("device_certifier"),
    "created_on",
).where((_t_d1.organization == q_organization_internal_id(Parameter("$1")))
        & (_t_d1.device_id == Parameter("$2"))).get_sql())
示例#8
0
async def get_realm_role_for_not_revoked(conn,
                                         organization_id,
                                         realm_id,
                                         users=None):
    now = pendulum.now()

    def _cook_role(row):
        if row["revoked_on"] and row["revoked_on"] <= now:
            return None
        if row["role"] is None:
            return None
        return STR_TO_REALM_ROLE[row["role"]]

    if users:

        query = """
WITH cte_current_realm_roles AS (
    SELECT DISTINCT ON(user_) user_, role
    FROM  realm_user_role
    WHERE realm = ({})
    ORDER BY user_, certified_on DESC
)
SELECT user_.user_id as user_id, user_.revoked_on as revoked_on, role
FROM user_
LEFT JOIN cte_current_realm_roles
ON user_._id = cte_current_realm_roles.user_
WHERE
    organization = ({})
    AND user_.user_id = ANY({}::VARCHAR[])
""".format(
            q_realm_internal_id(organization_id=Parameter("$1"),
                                realm_id=Parameter("$2")),
            q_organization_internal_id(Parameter("$1")),
            Parameter("$3"),
        )

        rep = await conn.fetch(query, organization_id, realm_id, users)
        roles = {row["user_id"]: _cook_role(row) for row in rep}
        for user in users or ():
            if user not in roles:
                raise RealmNotFoundError(f"User `{user}` doesn't exist")

        return roles

    else:

        query = """
SELECT DISTINCT ON(user_) ({}) as user_id, ({}) as revoked_on, role
FROM  realm_user_role
WHERE realm = ({})
ORDER BY user_, certified_on DESC
""".format(
            q_user(_id=Parameter("realm_user_role.user_")).select("user_id"),
            q_user(
                _id=Parameter("realm_user_role.user_")).select("revoked_on"),
            q_realm_internal_id(organization_id=Parameter("$1"),
                                realm_id=Parameter("$2")),
        )

        rep = await conn.fetch(query, organization_id, realm_id)

        return {
            row["user_id"]: _cook_role(row)
            for row in rep if _cook_role(row) is not None
        }
示例#9
0
    q_device_internal_id,
)

_q_get_user_devices = (Query.from_(t_device).select(
    t_device.device_id).where(t_device.user_ == q_user_internal_id(
        organization_id=Parameter("$1"), user_id=Parameter("$2"))).get_sql())

_q_get_not_revoked_users_for_human = (Query.from_(t_user).select(
    t_user.user_id).where((t_user.human == q_human_internal_id(
        organization_id=Parameter("$1"), email=Parameter("$2")))
                          & (t_user.revoked_on.isnull()
                             | t_user.revoked_on > Parameter("$3"))).get_sql())

_q_insert_human_if_not_exists = (Query.into(t_human).columns(
    "organization", "email",
    "label").insert(q_organization_internal_id(Parameter("$1")),
                    Parameter("$2"),
                    Parameter("$3")).on_conflict().do_nothing().get_sql())

_q_insert_user = (Query.into(t_user).columns(
    "organization",
    "user_id",
    "profile",
    "user_certificate",
    "redacted_user_certificate",
    "user_certifier",
    "created_on",
).insert(
    q_organization_internal_id(Parameter("$1")),
    Parameter("$2"),
    Parameter("$3"),
示例#10
0
    async def maintenance_save_reencryption_batch(
        self,
        organization_id: OrganizationID,
        author: DeviceID,
        realm_id: UUID,
        encryption_revision: int,
        batch: List[Tuple[UUID, int, bytes]],
    ) -> Tuple[int, int]:
        async with self.dbh.pool.acquire() as conn, conn.transaction():

            await _check_realm_and_maintenance_access(
                conn, organization_id, author, realm_id, encryption_revision
            )
            for vlob_id, version, blob in batch:
                query = """
INSERT INTO vlob_atom(
    organization,
    vlob_encryption_revision,
    vlob_id,
    version,
    blob,
    size,
    author,
    created_on,
    deleted_on
)
SELECT
    organization,
    ({}),
    $3,
    $4,
    $6,
    $7,
    author,
    created_on,
    deleted_on
FROM vlob_atom
WHERE
    organization = ({})
    AND vlob_id = $3
    AND version = $4
ON CONFLICT DO NOTHING
""".format(
                    q_vlob_encryption_revision_internal_id(
                        organization_id=Parameter("$1"),
                        realm_id=Parameter("$2"),
                        encryption_revision=Parameter("$5"),
                    ),
                    q_organization_internal_id(Parameter("$1")),
                )

                await conn.execute(
                    query,
                    organization_id,
                    realm_id,
                    vlob_id,
                    version,
                    encryption_revision,
                    blob,
                    len(blob),
                )

            query = """
SELECT (
    SELECT COUNT(*)
    FROM vlob_atom
    WHERE vlob_encryption_revision = ({})
),
(
    SELECT COUNT(*)
    FROM vlob_atom
    WHERE vlob_encryption_revision = ({})
)
""".format(
                q_vlob_encryption_revision_internal_id(
                    organization_id=Parameter("$1"),
                    realm_id=Parameter("$2"),
                    encryption_revision=Parameter("$3") - 1,
                ),
                q_vlob_encryption_revision_internal_id(
                    organization_id=Parameter("$1"),
                    realm_id=Parameter("$2"),
                    encryption_revision=Parameter("$3"),
                ),
            )

            rep = await conn.fetchrow(query, organization_id, realm_id, encryption_revision)

            return rep[0], rep[1]
示例#11
0
    async def update(
        self,
        organization_id: OrganizationID,
        author: DeviceID,
        encryption_revision: int,
        vlob_id: UUID,
        version: int,
        timestamp: pendulum.Pendulum,
        blob: bytes,
    ) -> None:
        async with self.dbh.pool.acquire() as conn, conn.transaction():

            realm_id = await _get_realm_id_from_vlob_id(conn, organization_id, vlob_id)
            await _check_realm_and_write_access(
                conn, organization_id, author, realm_id, encryption_revision
            )

            query = """
SELECT
    version,
    created_on
FROM vlob_atom
WHERE
    organization = ({})
    AND vlob_id = $2
ORDER BY version DESC LIMIT 1
""".format(
                q_organization_internal_id(Parameter("$1"))
            )

            previous = await conn.fetchrow(query, organization_id, vlob_id)
            if not previous:
                raise VlobNotFoundError(f"Vlob `{vlob_id}` doesn't exist")

            elif previous["version"] != version - 1:
                raise VlobVersionError()

            elif previous["created_on"] > timestamp:
                raise VlobTimestampError()

            query = """
INSERT INTO vlob_atom (
    organization,
    vlob_encryption_revision,
    vlob_id,
    version,
    blob,
    size,
    author,
    created_on
)
SELECT
    ({}),
    ({}),
    $5,
    $9,
    $6,
    $7,
    ({}),
    $8
RETURNING _id
""".format(
                q_organization_internal_id(Parameter("$1")),
                q_vlob_encryption_revision_internal_id(
                    organization_id=Parameter("$1"),
                    realm_id=Parameter("$3"),
                    encryption_revision=Parameter("$4"),
                ),
                q_device_internal_id(organization_id=Parameter("$1"), device_id=Parameter("$2")),
            )

            try:
                vlob_atom_internal_id = await conn.fetchval(
                    query,
                    organization_id,
                    author,
                    realm_id,
                    encryption_revision,
                    vlob_id,
                    blob,
                    len(blob),
                    timestamp,
                    version,
                )

            except UniqueViolationError:
                # Should not occurs in theory given we are in a transaction
                raise VlobVersionError()

            await _vlob_updated(
                conn, vlob_atom_internal_id, organization_id, author, realm_id, vlob_id, version
            )
示例#12
0
    async def create(
        self,
        organization_id: OrganizationID,
        author: DeviceID,
        realm_id: UUID,
        encryption_revision: int,
        vlob_id: UUID,
        timestamp: pendulum.Pendulum,
        blob: bytes,
    ) -> None:
        async with self.dbh.pool.acquire() as conn, conn.transaction():
            await _check_realm_and_write_access(
                conn, organization_id, author, realm_id, encryption_revision
            )

            # Actually create the vlob
            try:
                query = """
INSERT INTO vlob_atom (
    organization,
    vlob_encryption_revision,
    vlob_id,
    version,
    blob,
    size,
    author,
    created_on
)
SELECT
    ({}),
    ({}),
    $5,
    1,
    $6,
    $7,
    ({}),
    $8
RETURNING _id
""".format(
                    q_organization_internal_id(organization_id=Parameter("$1")),
                    Query.from_(t_vlob_encryption_revision)
                    .where(
                        (
                            t_vlob_encryption_revision.realm
                            == q_realm_internal_id(
                                organization_id=Parameter("$1"), realm_id=Parameter("$3")
                            )
                        )
                        & (t_vlob_encryption_revision.encryption_revision == Parameter("$4"))
                    )
                    .select("_id"),
                    q_device_internal_id(
                        organization_id=Parameter("$1"), device_id=Parameter("$2")
                    ),
                )

                vlob_atom_internal_id = await conn.fetchval(
                    query,
                    organization_id,
                    author,
                    realm_id,
                    encryption_revision,
                    vlob_id,
                    blob,
                    len(blob),
                    timestamp,
                )

            except UniqueViolationError:
                raise VlobAlreadyExistsError()

            await _vlob_updated(
                conn, vlob_atom_internal_id, organization_id, author, realm_id, vlob_id
            )
示例#13
0
        expiration_date = EXCLUDED.expiration_date
    WHERE organization.root_verify_key is NULL
""")

_q_get_organization = (q_organization(Parameter("$1")).select(
    "bootstrap_token", "root_verify_key", "expiration_date").get_sql())

_q_bootstrap_organization = (Query.update(t_organization).where(
    (t_organization.organization_id == Parameter("$1"))
    & (t_organization.bootstrap_token == Parameter("$2"))
    & (t_organization.root_verify_key.isnull())).set(
        t_organization.root_verify_key, Parameter("$3")).get_sql())

_q_get_stats = Query.select(
    Query.from_(t_user).where(
        t_user.organization == q_organization_internal_id(Parameter(
            "$1"))).select(fn.Count("*")).as_("users"),
    Query.from_(t_vlob_atom).where(
        t_vlob_atom.organization == q_organization_internal_id(Parameter(
            "$1"))).select(fn.Coalesce(fn.Sum(t_vlob_atom.size),
                                       0)).as_("metadata_size"),
    Query.from_(t_block).where(
        t_block.organization == q_organization_internal_id(Parameter(
            "$1"))).select(fn.Coalesce(fn.Sum(t_block.size),
                                       0)).as_("data_size"),
).get_sql()

_q_update_organisation_expiration_date = (Query.update(t_organization).where(
    (t_organization.organization_id == Parameter("$1"))).set(
        t_organization.expiration_date, Parameter("$2")).get_sql())

示例#14
0
    .select(t_user.user_id)
    .where(
        (
            t_user.human
            == q_human_internal_id(organization_id=Parameter("$1"), email=Parameter("$2"))
        )
        & (t_user.revoked_on.isnull() | t_user.revoked_on > Parameter("$3"))
    )
    .get_sql()
)


_q_insert_human_if_not_exists = (
    Query.into(t_human)
    .columns("organization", "email", "label")
    .insert(q_organization_internal_id(Parameter("$1")), Parameter("$2"), Parameter("$3"))
    .on_conflict()
    .do_nothing()
    .get_sql()
)


_q_insert_user = (
    Query.into(t_user)
    .columns(
        "organization", "user_id", "is_admin", "user_certificate", "user_certifier", "created_on"
    )
    .insert(
        q_organization_internal_id(Parameter("$1")),
        Parameter("$2"),
        Parameter("$3"),