Ejemplo n.º 1
0
    async def cancel_device_invitation(self, organization_id: OrganizationID,
                                       device_id: DeviceID) -> None:
        async with self.dbh.pool.acquire() as conn:
            async with conn.transaction():

                if await self._device_exists(conn, organization_id, device_id):
                    raise UserAlreadyExistsError(
                        f"Device `{device_id}` already exists")

                result = await conn.execute(
                    """
DELETE FROM device_invitations
WHERE
    organization = (
        SELECT _id from organizations WHERE organization_id = $1
    )
    AND device_id = $2
""",
                    organization_id,
                    device_id,
                )
                if result not in ("DELETE 1", "DELETE 0"):
                    raise UserError(f"Deletion error: {result}")

                await send_signal(
                    conn,
                    "device.invitation.cancelled",
                    organization_id=organization_id,
                    device_id=device_id,
                )
Ejemplo n.º 2
0
async def _create_user(conn, organization_id: OrganizationID, user: User,
                       first_device: Device) -> None:
    try:
        result = await conn.execute(
            _q_insert_user,
            organization_id,
            user.user_id,
            user.is_admin,
            user.user_certificate,
            user.user_certifier,
            user.created_on,
        )
    except UniqueViolationError:
        raise UserAlreadyExistsError(f"User `{user.user_id}` already exists")

    if result != "INSERT 0 1":
        raise UserError(f"Insertion error: {result}")

    await _create_device(conn,
                         organization_id,
                         first_device,
                         first_device=True)

    await send_signal(
        conn,
        "user.created",
        organization_id=organization_id,
        user_id=user.user_id,
        user_certificate=user.user_certificate,
        first_device_id=first_device.device_id,
        first_device_certificate=first_device.device_certificate,
    )
Ejemplo n.º 3
0
async def query_revoke_user(
    conn,
    organization_id: OrganizationID,
    user_id: UserID,
    revoked_user_certificate: bytes,
    revoked_user_certifier: DeviceID,
    revoked_on: pendulum.Pendulum = None,
) -> None:
    result = await conn.execute(
        _q_revoke_user,
        organization_id,
        user_id,
        revoked_user_certificate,
        revoked_user_certifier,
        revoked_on or pendulum.now(),
    )

    if result != "UPDATE 1":
        # TODO: avoid having to do another query to find the error
        err_result = await conn.fetchrow(_q_revoke_user_error, organization_id,
                                         user_id)
        if not err_result:
            raise UserNotFoundError(user_id)

        elif err_result[0]:
            raise UserAlreadyRevokedError()

        else:
            raise UserError(f"Update error: {result}")
    else:
        await send_signal(conn,
                          "user.revoked",
                          organization_id=organization_id,
                          user_id=user_id)
Ejemplo n.º 4
0
async def query_revoke_user(
    conn,
    organization_id: OrganizationID,
    user_id: UserID,
    revoked_user_certificate: bytes,
    revoked_user_certifier: DeviceID,
    revoked_on: Optional[pendulum.DateTime] = None,
) -> None:
    result = await conn.execute(*_q_revoke_user(
        organization_id=organization_id,
        user_id=user_id,
        revoked_user_certificate=revoked_user_certificate,
        revoked_user_certifier=revoked_user_certifier,
        revoked_on=revoked_on or pendulum.now(),
    ))

    if result != "UPDATE 1":
        # TODO: avoid having to do another query to find the error
        err_result = await conn.fetchrow(*_q_revoke_user_error(
            organization_id=organization_id, user_id=user_id))
        if not err_result:
            raise UserNotFoundError(user_id)

        elif err_result[0]:
            raise UserAlreadyRevokedError()

        else:
            raise UserError(f"Update error: {result}")
    else:
        await send_signal(conn,
                          BackendEvent.USER_REVOKED,
                          organization_id=organization_id,
                          user_id=user_id)
Ejemplo n.º 5
0
async def _create_device(conn,
                         organization_id: OrganizationID,
                         device: Device,
                         first_device: bool = False) -> None:
    if not first_device:
        existing_devices = await conn.fetch(_q_get_user_devices,
                                            organization_id, device.user_id)
        if not existing_devices:
            raise UserNotFoundError(f"User `{device.user_id}` doesn't exists")

        if device.device_id in itertools.chain(*existing_devices):
            raise UserAlreadyExistsError(
                f"Device `{device.device_id}` already exists")

    try:
        result = await conn.execute(
            _q_insert_device,
            organization_id,
            device.user_id,
            device.device_id,
            device.device_certificate,
            device.device_certifier,
            device.created_on,
        )
    except UniqueViolationError:
        raise UserAlreadyExistsError(
            f"Device `{device.device_id}` already exists")

    if result != "INSERT 0 1":
        raise UserError(f"Insertion error: {result}")
Ejemplo n.º 6
0
async def query_cancel_user_invitation(conn, organization_id: OrganizationID,
                                       user_id: UserID) -> None:
    if await _user_exists(conn, organization_id, user_id):
        raise UserAlreadyExistsError(f"User `{user_id}` already exists")

    result = await conn.execute(_q_delete_invitation, organization_id, user_id)
    if result not in ("DELETE 1", "DELETE 0"):
        raise UserError(f"Deletion error: {result}")
Ejemplo n.º 7
0
    async def revoke_device(
        self,
        organization_id: OrganizationID,
        device_id: DeviceID,
        certified_revocation: bytes,
        revocation_certifier: DeviceID,
    ) -> None:
        async with self.dbh.pool.acquire() as conn:
            async with conn.transaction():

                result = await conn.execute(
                    """
UPDATE devices SET
    certified_revocation = $3,
    revocation_certifier = (
        SELECT _id FROM devices WHERE device_id = $4
    ),
    revocated_on = $5
WHERE
    organization = (
        SELECT _id from organizations WHERE organization_id = $1
    )
    AND device_id = $2
    AND revocated_on IS NULL
""",
                    organization_id,
                    device_id,
                    certified_revocation,
                    revocation_certifier,
                    pendulum.now(),
                )

                if result != "UPDATE 1":
                    # TODO: avoid having to do another query to find the error
                    err_result = await conn.fetchrow(
                        """
SELECT revocated_on
FROM devices
WHERE
    organization = (
        SELECT _id from organizations WHERE organization_id = $1
    )
    AND device_id = $2
""",
                        organization_id,
                        device_id,
                    )
                    if not err_result:
                        raise UserNotFoundError(device_id)
                    if err_result[0]:
                        raise UserAlreadyRevokedError()

                    else:
                        raise UserError(f"Update error: {result}")
Ejemplo n.º 8
0
async def query_cancel_device_invitation(conn, organization_id: OrganizationID,
                                         device_id: DeviceID) -> None:
    if await _device_exists(conn, organization_id, device_id):
        raise UserAlreadyExistsError(f"Device `{device_id}` already exists")

    result = await conn.execute(_q_delete_invitation, organization_id,
                                device_id)
    if result not in ("DELETE 1", "DELETE 0"):
        raise UserError(f"Deletion error: {result}")

    await send_signal(conn,
                      "device.invitation.cancelled",
                      organization_id=organization_id,
                      device_id=device_id)
Ejemplo n.º 9
0
async def query_create_user_invitation(conn, organization_id: OrganizationID,
                                       invitation: UserInvitation) -> None:
    if await _user_exists(conn, organization_id, invitation.user_id):
        raise UserAlreadyExistsError(
            f"User `{invitation.user_id}` already exists")

    result = await conn.execute(*_q_insert_invitation(
        organization_id=organization_id,
        creator=invitation.creator,
        user_id=invitation.user_id,
        created_on=invitation.created_on,
    ))

    if result not in ("INSERT 0 1", "UPDATE 1"):
        raise UserError(f"Insertion error: {result}")
Ejemplo n.º 10
0
async def query_cancel_device_invitation(conn, organization_id: OrganizationID,
                                         device_id: DeviceID) -> None:
    if await _device_exists(conn, organization_id, device_id):
        raise UserAlreadyExistsError(f"Device `{device_id}` already exists")

    result = await conn.execute(*_q_delete_invitation(
        organization_id=organization_id, device_id=device_id))
    if result not in ("DELETE 1", "DELETE 0"):
        raise UserError(f"Deletion error: {result}")

    await send_signal(
        conn,
        BackendEvent.DEVICE_INVITATION_CANCELLED,
        organization_id=organization_id,
        device_id=device_id,
    )
Ejemplo n.º 11
0
async def _create_device_invitation(conn, organization_id: OrganizationID,
                                    invitation: DeviceInvitation) -> None:
    if await _device_exists(conn, organization_id, invitation.device_id):
        raise UserAlreadyExistsError(
            f"Device `{invitation.device_id}` already exists")

    result = await conn.execute(
        _q_insert_invitation,
        organization_id,
        invitation.creator,
        invitation.device_id,
        invitation.created_on,
    )

    if result not in ("INSERT 0 1", "UPDATE 1"):
        raise UserError(f"Insertion error: {result}")
Ejemplo n.º 12
0
async def _do_create_user_with_human_handle(conn,
                                            organization_id: OrganizationID,
                                            user: User,
                                            first_device: Device) -> None:
    # Create human handle if needed
    await conn.execute(
        _q_insert_human_if_not_exists,
        organization_id,
        user.human_handle.email,
        user.human_handle.label,
    )

    # Now insert the new user
    try:
        result = await conn.execute(
            _q_insert_user_with_human_handle,
            organization_id,
            user.user_id,
            user.profile.value,
            user.user_certificate,
            user.redacted_user_certificate,
            user.user_certifier,
            user.created_on,
            user.human_handle.email,
        )

    except UniqueViolationError:
        raise UserAlreadyExistsError(f"User `{user.user_id}` already exists")

    if result != "INSERT 0 1":
        raise UserError(f"Insertion error: {result}")

    # Finally make sure there is only one non-revoked user with this human handle
    now = pendulum_now()
    not_revoked_users = await conn.fetch(_q_get_not_revoked_users_for_human,
                                         organization_id,
                                         user.human_handle.email, now)
    if len(not_revoked_users
           ) != 1 or not_revoked_users[0]["user_id"] != user.user_id:
        # Exception cancels the transaction so the user insertion is automatically cancelled
        raise UserAlreadyExistsError(
            f"Human handle `{user.human_handle}` already corresponds to a non-revoked user"
        )
Ejemplo n.º 13
0
async def _do_create_user_without_human_handle(
    conn, organization_id: OrganizationID, user: User, first_device: Device
) -> None:
    try:
        result = await conn.execute(
            _q_insert_user,
            organization_id,
            user.user_id,
            user.is_admin,
            user.user_certificate,
            user.user_certifier,
            user.created_on,
        )

    except UniqueViolationError:
        raise UserAlreadyExistsError(f"User `{user.user_id}` already exists")

    if result != "INSERT 0 1":
        raise UserError(f"Insertion error: {result}")
Ejemplo n.º 14
0
    async def set_user_admin(self, organization_id: OrganizationID,
                             user_id: UserID, is_admin: bool) -> None:
        await self.get_user(organization_id, user_id)

        async with self.dbh.pool.acquire() as conn:
            result = await conn.execute(
                """
UPDATE users SET
    is_admin = $3
WHERE
    organization = (
        SELECT _id from organizations WHERE organization_id = $1
    )
    AND user_id = $2
""",
                organization_id,
                user_id,
                is_admin,
            )
            if result != "UPDATE 1":
                raise UserError(f"Update error: {result}")
Ejemplo n.º 15
0
    async def create_device_invitation(self, organization_id: OrganizationID,
                                       invitation: DeviceInvitation) -> None:
        async with self.dbh.pool.acquire() as conn:
            async with conn.transaction():

                if await self._device_exists(conn, organization_id,
                                             invitation.device_id):
                    raise UserAlreadyExistsError(
                        f"Device `{invitation.device_id}` already exists")

                result = await conn.execute(
                    """
INSERT INTO device_invitations (
    organization,
    creator,
    device_id,
    created_on
)
VALUES (
    (SELECT _id FROM organizations WHERE organization_id = $1),
    (SELECT _id FROM devices WHERE device_id = $2),
    $3, $4
)
ON CONFLICT (device_id)
DO UPDATE
SET
    organization = excluded.organization,
    creator = excluded.creator,
    created_on = excluded.created_on
""",
                    organization_id,
                    invitation.creator,
                    invitation.device_id,
                    invitation.created_on,
                )

                if result not in ("INSERT 0 1", "UPDATE 1"):
                    raise UserError(f"Insertion error: {result}")
Ejemplo n.º 16
0
    async def _create_device(self, conn, organization_id: OrganizationID,
                             device: Device) -> None:
        existing_devices = await conn.fetch(
            """
SELECT device_id FROM devices
WHERE user_ = (
    SELECT _id FROM users
    WHERE
        organization = (
            SELECT _id from organizations WHERE organization_id = $1
        )
        AND user_id = $2
)
            """,
            organization_id,
            device.user_id,
        )
        if not existing_devices:
            raise UserNotFoundError(f"User `{device.user_id}` doesn't exists")

        if device.device_id in itertools.chain(*existing_devices):
            raise UserAlreadyExistsError(
                f"Device `{device.device_id}` already exists")

        result = await conn.execute(
            """
INSERT INTO devices (
    organization,
    user_,
    device_id,
    certified_device,
    device_certifier,
    created_on,
    revocated_on,
    certified_revocation,
    revocation_certifier
)
SELECT
    _id,
    (
        SELECT _id
        FROM users
        WHERE
            user_id = $2
            AND organization = organizations._id
    ),
    $3, $4,
    (
        SELECT _id
        FROM devices
        WHERE
            device_id = $5
            AND organization = organizations._id
    ),
    $6, $7, $8, $9
FROM organizations
WHERE organization_id = $1
""",
            organization_id,
            device.user_id,
            device.device_id,
            device.certified_device,
            device.device_certifier,
            device.created_on,
            device.revocated_on,
            device.certified_revocation,
            device.revocation_certifier,
        )

        if result != "INSERT 0 1":
            raise UserError(f"Insertion error: {result}")
Ejemplo n.º 17
0
    async def _create_user(conn, organization_id: OrganizationID,
                           user: User) -> None:
        try:
            result = await conn.execute(
                """
INSERT INTO users (
    organization,
    user_id,
    is_admin,
    certified_user,
    user_certifier,
    created_on
)
SELECT
    _id,
    $2, $3, $4,
    (
        SELECT _id
        FROM devices
        WHERE
            device_id = $5
            AND organization = organizations._id
    ),
    $6
FROM organizations
WHERE organization_id = $1
""",
                organization_id,
                user.user_id,
                user.is_admin,
                user.certified_user,
                user.user_certifier,
                user.created_on,
            )
        except UniqueViolationError:
            raise UserAlreadyExistsError(
                f"User `{user.user_id}` already exists")

        if result != "INSERT 0 1":
            raise UserError(f"Insertion error: {result}")

        await conn.executemany(
            """
INSERT INTO devices (
    organization,
    user_,
    device_id,
    certified_device,
    device_certifier,
    created_on,
    revocated_on,
    certified_revocation,
    revocation_certifier
)
SELECT
    _id,
    (
        SELECT _id
        FROM users
        WHERE
            user_id = $2
            AND organization = organizations._id
    ),
    $3, $4,
    (
        SELECT _id
        FROM devices
        WHERE
            device_id = $5
            AND organization = organizations._id
    ),
    $6, $7, $8, $9
FROM organizations
WHERE organization_id = $1
""",
            [(
                organization_id,
                device.user_id,
                device.device_id,
                device.certified_device,
                device.device_certifier,
                device.created_on,
                device.revocated_on,
                device.certified_revocation,
                device.revocation_certifier,
            ) for device in user.devices.values()],
        )