Esempio n. 1
0
async def _get_user(conn, organization_id: OrganizationID,
                    user_id: UserID) -> User:
    row = await conn.fetchrow(
        *_q_get_user(organization_id=organization_id.str, user_id=user_id.str))
    if not row:
        raise UserNotFoundError(user_id)

    human_handle = None
    if row["human_email"]:
        human_handle = HumanHandle(email=row["human_email"],
                                   label=row["human_label"])

    return User(
        user_id=user_id,
        human_handle=human_handle,
        profile=UserProfile(row["profile"]),
        user_certificate=row["user_certificate"],
        redacted_user_certificate=row["redacted_user_certificate"],
        user_certifier=DeviceID(row["user_certifier"])
        if row["user_certifier"] else None,
        created_on=row["created_on"],
        revoked_on=row["revoked_on"],
        revoked_user_certificate=row["revoked_user_certificate"],
        revoked_user_certifier=DeviceID(row["revoked_user_certifier"])
        if row["revoked_user_certifier"] else None,
    )
Esempio n. 2
0
    async def _get_device_invitation(self, conn,
                                     organization_id: OrganizationID,
                                     device_id: DeviceID):
        if await self._device_exists(conn, organization_id, device_id):
            raise UserAlreadyExistsError(
                f"Device `{device_id}` already exists")

        result = await conn.fetchrow(
            """
SELECT device_invitations.device_id, devices.device_id, device_invitations.created_on
FROM device_invitations
LEFT JOIN devices ON device_invitations.creator = devices._id
WHERE
    device_invitations.organization = (
        SELECT _id from organizations WHERE organization_id = $1
    )
    AND device_invitations.device_id = $2
""",
            organization_id,
            device_id,
        )
        if not result:
            raise UserNotFoundError(device_id)

        return DeviceInvitation(device_id=DeviceID(result[0]),
                                creator=DeviceID(result[1]),
                                created_on=result[2])
Esempio n. 3
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}")
Esempio 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)
Esempio n. 5
0
    async def _get_user_invitation(self, conn, organization_id: OrganizationID,
                                   user_id: UserID):
        if await self._user_exists(conn, organization_id, user_id):
            raise UserAlreadyExistsError(f"User `{user_id}` already exists")

        result = await conn.fetchrow(
            """
SELECT user_invitations.user_id, devices.device_id, user_invitations.created_on
FROM user_invitations
LEFT JOIN devices ON user_invitations.creator = devices._id
WHERE
    user_invitations.organization = (
        SELECT _id from organizations WHERE organization_id = $1
    )
    AND user_invitations.user_id = $2
""",
            organization_id,
            user_id,
        )
        if not result:
            raise UserNotFoundError(user_id)

        return UserInvitation(user_id=UserID(result[0]),
                              creator=DeviceID(result[1]),
                              created_on=result[2])
Esempio n. 6
0
    async def revoke_user(
        self,
        organization_id: OrganizationID,
        user_id: UserID,
        revoked_user_certificate: bytes,
        revoked_user_certifier: DeviceID,
        revoked_on: pendulum.Pendulum = None,
    ) -> None:
        org = self._organizations[organization_id]

        try:
            user = org.users[user_id]

        except KeyError:
            raise UserNotFoundError(user_id)

        if user.revoked_on:
            raise UserAlreadyRevokedError()

        org.users[user_id] = user.evolve(
            revoked_on=revoked_on or pendulum.now(),
            revoked_user_certificate=revoked_user_certificate,
            revoked_user_certifier=revoked_user_certifier,
        )
        if user.human_handle:
            del org.human_handle_to_user_id[user.human_handle]

        await self._send_event("user.revoked",
                               organization_id=organization_id,
                               user_id=user_id)
Esempio n. 7
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)
Esempio n. 8
0
    async def revoke_device(
        self,
        organization_id: OrganizationID,
        device_id: DeviceID,
        certified_revocation: bytes,
        revocation_certifier: DeviceID,
    ) -> None:
        org = self._organizations[organization_id]

        user = await self.get_user(organization_id, device_id.user_id)
        try:
            if user.devices[device_id.device_name].revocated_on:
                raise UserAlreadyRevokedError()

        except KeyError:
            raise UserNotFoundError(device_id)

        patched_devices = []
        for device in user.devices.values():
            if device.device_id == device_id:
                device = device.evolve(
                    revocated_on=pendulum.now(),
                    certified_revocation=certified_revocation,
                    revocation_certifier=revocation_certifier,
                )
            patched_devices.append(device)

        org._users[device_id.user_id] = user.evolve(devices=DevicesMapping(
            *patched_devices))
Esempio n. 9
0
async def _get_user(conn, organization_id: OrganizationID,
                    user_id: UserID) -> User:
    row = await conn.fetchrow(
        *_q_get_user(organization_id=organization_id, user_id=user_id))
    if not row:
        raise UserNotFoundError(user_id)

    if row["human_email"]:
        human_handle = HumanHandle(email=row["human_email"],
                                   label=row["human_label"])
    else:
        human_handle = None

    return User(
        user_id=user_id,
        human_handle=human_handle,
        profile=STR_TO_USER_PROFILE[row["profile"]],
        user_certificate=row["user_certificate"],
        redacted_user_certificate=row["redacted_user_certificate"],
        user_certifier=row["user_certifier"],
        created_on=row["created_on"],
        revoked_on=row["revoked_on"],
        revoked_user_certificate=row["revoked_user_certificate"],
        revoked_user_certifier=row["revoked_user_certifier"],
    )
Esempio n. 10
0
async def query_get_user_with_device(
        conn, organization_id: OrganizationID,
        device_id: DeviceID) -> Tuple[User, Device]:
    d_row = await conn.fetchrow(_q_get_device, organization_id, device_id)
    u_row = await conn.fetchrow(_q_get_user, organization_id,
                                device_id.user_id)
    if not u_row or not d_row:
        raise UserNotFoundError(device_id)

    device = Device(
        device_id=device_id,
        device_label=d_row["device_label"],
        device_certificate=d_row["device_certificate"],
        redacted_device_certificate=d_row["redacted_device_certificate"],
        device_certifier=d_row["device_certifier"],
        created_on=d_row["created_on"],
    )
    user = User(
        user_id=device_id.user_id,
        profile=STR_TO_USER_PROFILE[u_row["profile"]],
        user_certificate=u_row["user_certificate"],
        redacted_user_certificate=u_row["redacted_user_certificate"],
        user_certifier=u_row["user_certifier"],
        created_on=u_row["created_on"],
        revoked_on=u_row["revoked_on"],
        revoked_user_certificate=u_row["revoked_user_certificate"],
        revoked_user_certifier=u_row["revoked_user_certifier"],
    )
    return user, device
Esempio n. 11
0
    async def get_device(self, organization_id: OrganizationID,
                         device_id: DeviceID) -> Device:
        user = await self.get_user(organization_id, device_id.user_id)
        try:
            return user.devices[device_id.device_name]

        except KeyError:
            raise UserNotFoundError(device_id)
Esempio n. 12
0
    def _get_user(self, organization_id: OrganizationID,
                  user_id: UserID) -> User:
        org = self._organizations[organization_id]

        try:
            return org.users[user_id]

        except KeyError:
            raise UserNotFoundError(user_id)
Esempio n. 13
0
    def _get_device(self, organization_id: OrganizationID,
                    device_id: DeviceID) -> Device:
        org = self._organizations[organization_id]

        try:
            return org.devices[device_id.user_id][device_id.device_name]

        except KeyError:
            raise UserNotFoundError(device_id)
Esempio n. 14
0
    async def get_user_invitation(self, organization_id: OrganizationID,
                                  user_id: UserID) -> UserInvitation:
        org = self._organizations[organization_id]

        if user_id in org.users:
            raise UserAlreadyExistsError(user_id)
        try:
            return org.invitations[user_id]
        except KeyError:
            raise UserNotFoundError(user_id)
Esempio n. 15
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}")
Esempio n. 16
0
async def _get_device_invitation(conn, organization_id: OrganizationID,
                                 device_id: DeviceID) -> DeviceInvitation:
    if await _device_exists(conn, organization_id, device_id):
        raise UserAlreadyExistsError(f"Device `{device_id}` already exists")

    result = await conn.fetchrow(_q_get_invitation, organization_id, device_id)
    if not result:
        raise UserNotFoundError(device_id)

    return DeviceInvitation(device_id=DeviceID(result[0]),
                            creator=DeviceID(result[1]),
                            created_on=result[2])
Esempio n. 17
0
async def _get_device(conn, organization_id: OrganizationID,
                      device_id: DeviceID) -> Device:
    row = await conn.fetchrow(_q_get_device, organization_id, device_id)
    if not row:
        raise UserNotFoundError(device_id)

    return Device(
        device_id=device_id,
        device_certificate=row["device_certificate"],
        device_certifier=row["device_certifier"],
        created_on=row["created_on"],
    )
Esempio n. 18
0
async def _get_user_invitation(conn, organization_id: OrganizationID,
                               user_id: UserID):
    if await _user_exists(conn, organization_id, user_id):
        raise UserAlreadyExistsError(f"User `{user_id}` already exists")

    result = await conn.fetchrow(_q_get_invitation, organization_id, user_id)
    if not result:
        raise UserNotFoundError(user_id)

    return UserInvitation(user_id=UserID(result[0]),
                          creator=DeviceID(result[1]),
                          created_on=result[2])
Esempio n. 19
0
    async def get_device_invitation(self, organization_id: OrganizationID,
                                    device_id: DeviceID) -> DeviceInvitation:
        org = self._organizations[organization_id]

        try:
            org._users[device_id.user_id].devices[device_id.device_name]
            raise UserAlreadyExistsError(device_id)
        except KeyError:
            pass
        try:
            return org._invitations[device_id]
        except KeyError:
            raise UserNotFoundError(device_id)
Esempio n. 20
0
    async def get_device_invitation(self, organization_id: OrganizationID,
                                    device_id: DeviceID) -> DeviceInvitation:
        org = self._organizations[organization_id]

        user_devices = self._get_user_devices(organization_id,
                                              device_id.user_id)
        if device_id.device_name in user_devices:
            raise UserAlreadyExistsError(device_id)

        try:
            return org.invitations[device_id]

        except KeyError:
            raise UserNotFoundError(device_id)
Esempio n. 21
0
async def _get_device(conn, organization_id: OrganizationID,
                      device_id: DeviceID) -> Device:
    row = await conn.fetchrow(*_q_get_device(
        organization_id=organization_id.str, device_id=device_id.str))
    if not row:
        raise UserNotFoundError(device_id)

    return Device(
        device_id=device_id,
        device_label=DeviceLabel(row["device_label"]),
        device_certificate=row["device_certificate"],
        redacted_device_certificate=row["redacted_device_certificate"],
        device_certifier=DeviceID(row["device_certifier"]),
        created_on=row["created_on"],
    )
Esempio n. 22
0
async def _get_user(conn, organization_id: OrganizationID,
                    user_id: UserID) -> User:
    row = await conn.fetchrow(_q_get_user, organization_id, user_id)
    if not row:
        raise UserNotFoundError(user_id)

    return User(
        user_id=user_id,
        is_admin=row["is_admin"],
        user_certificate=row["user_certificate"],
        user_certifier=row["user_certifier"],
        created_on=row["created_on"],
        revoked_on=row["revoked_on"],
        revoked_user_certificate=row["revoked_user_certificate"],
        revoked_user_certifier=row["revoked_user_certifier"],
    )
Esempio n. 23
0
async def _get_user(conn, organization_id: OrganizationID,
                    user_id: UserID) -> User:
    row = await conn.fetchrow(_q_get_user, organization_id, user_id)
    if not row:
        raise UserNotFoundError(user_id)

    return User(
        user_id=user_id,
        profile=STR_TO_USER_PROFILE[row["profile"]],
        user_certificate=row["user_certificate"],
        redacted_user_certificate=row["redacted_user_certificate"],
        user_certifier=row["user_certifier"],
        created_on=row["created_on"],
        revoked_on=row["revoked_on"],
        revoked_user_certificate=row["revoked_user_certificate"],
        revoked_user_certifier=row["revoked_user_certifier"],
    )
Esempio n. 24
0
async def query_get_user_with_device(
        conn, organization_id: OrganizationID,
        device_id: DeviceID) -> Tuple[User, Device]:
    d_row = await conn.fetchrow(*_q_get_device(
        organization_id=organization_id.str, device_id=device_id.str))
    u_row = await conn.fetchrow(*_q_get_user(
        organization_id=organization_id.str, user_id=device_id.user_id.str))
    if not u_row or not d_row:
        raise UserNotFoundError(device_id)

    human_handle = None
    if u_row["human_email"]:
        human_handle = HumanHandle(email=u_row["human_email"],
                                   label=u_row["human_label"])

    device = Device(
        device_id=device_id,
        device_label=DeviceLabel(d_row["device_label"])
        if d_row["device_label"] else None,
        device_certificate=d_row["device_certificate"],
        redacted_device_certificate=d_row["redacted_device_certificate"],
        device_certifier=DeviceID(d_row["device_certifier"])
        if d_row["device_certifier"] else None,
        created_on=d_row["created_on"],
    )
    user = User(
        user_id=device_id.user_id,
        human_handle=human_handle,
        profile=UserProfile(u_row["profile"]),
        user_certificate=u_row["user_certificate"],
        redacted_user_certificate=u_row["redacted_user_certificate"],
        user_certifier=DeviceID(u_row["user_certifier"])
        if u_row["user_certifier"] else None,
        created_on=u_row["created_on"],
        revoked_on=u_row["revoked_on"],
        revoked_user_certificate=u_row["revoked_user_certificate"],
        revoked_user_certifier=DeviceID(u_row["revoked_user_certifier"])
        if u_row["revoked_user_certifier"] else None,
    )
    return user, device
Esempio n. 25
0
    async def create_device(self,
                            organization_id: OrganizationID,
                            device: Device,
                            encrypted_answer: bytes = b"") -> None:
        org = self._organizations[organization_id]

        if device.user_id not in org.users:
            raise UserNotFoundError(f"User `{device.user_id}` doesn't exists")

        user_devices = org.devices[device.user_id]
        if device.device_name in user_devices:
            raise UserAlreadyExistsError(
                f"Device `{device.device_id}` already exists")

        user_devices[device.device_name] = device
        await self._send_event(
            "device.created",
            organization_id=organization_id,
            device_id=device.device_id,
            device_certificate=device.device_certificate,
            encrypted_answer=encrypted_answer,
        )
Esempio n. 26
0
    async def create_device(self,
                            organization_id: OrganizationID,
                            device: Device,
                            encrypted_answer: bytes = b"") -> None:
        org = self._organizations[organization_id]

        if device.user_id not in org._users:
            raise UserNotFoundError(f"User `{device.user_id}` doesn't exists")

        user = org._users[device.user_id]
        if device.device_name in user.devices:
            raise UserAlreadyExistsError(
                f"Device `{device.device_id}` already exists")

        org._users[device.user_id] = user.evolve(
            devices=DevicesMapping(*user.devices.values(), device))
        self.event_bus.send(
            "device.created",
            organization_id=organization_id,
            device_id=device.device_id,
            encrypted_answer=encrypted_answer,
        )
Esempio n. 27
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}")
Esempio n. 28
0
    async def _get_user(self, conn, organization_id: OrganizationID,
                        user_id: UserID) -> User:
        user_result = await conn.fetchrow(
            """
SELECT
    is_admin,
    certified_user,
    (SELECT device_id FROM devices WHERE _id = user_certifier),
    created_on
FROM users
WHERE
    organization = (
        SELECT _id from organizations WHERE organization_id = $1
    )
    AND user_id = $2
""",
            organization_id,
            user_id,
        )
        if not user_result:
            raise UserNotFoundError(user_id)

        devices_results = await conn.fetch(
            """
SELECT
    d1.device_id,
    d1.certified_device,
    (
        SELECT devices.device_id FROM devices WHERE devices._id = d1.device_certifier
    ) AS device_certifier,
    d1.created_on,
    d1.revocated_on,
    d1.certified_revocation,
    (
        SELECT devices.device_id FROM devices WHERE devices._id = d1.revocation_certifier
    ) as revocation_certifier
FROM devices as d1
WHERE user_ = (
    SELECT _id FROM users WHERE
        organization = (
            SELECT _id from organizations WHERE organization_id = $1
        )
        AND user_id = $2
);
""",
            organization_id,
            user_id,
        )
        devices = DevicesMapping(*[
            Device(DeviceID(device_result[0]), *device_result[1:])
            for device_result in devices_results
        ])

        return User(
            user_id=UserID(user_id),
            is_admin=user_result[0],
            certified_user=user_result[1],
            user_certifier=user_result[2],
            created_on=user_result[3],
            devices=devices,
        )