Compare commits

..

No commits in common. "b421d6f79b134284092c7bba0cdcfc6751f5dc98" and "821d72a7736ddaed552e486cb5be487de4182f20" have entirely different histories.

4 changed files with 18 additions and 68 deletions

View file

@ -252,15 +252,12 @@ class EasyRSA:
def issue( def issue(
self, self,
cert_type: CertificateType = CertificateType.client, cert_type: CertificateType = CertificateType.client,
dn: DistinguishedName | None = None, dn: DistinguishedName = DistinguishedName.build(),
) -> crypto.X509 | None: ) -> crypto.X509 | None:
""" """
Issue a client or server certificate Issue a client or server certificate
""" """
if dn is None:
dn = DistinguishedName.build()
if not (cert_type is CertificateType.client if not (cert_type is CertificateType.client
or cert_type is CertificateType.server): or cert_type is CertificateType.server):
return None return None

View file

@ -32,7 +32,7 @@ class Responses:
"content": None, "content": None,
} }
NEEDS_USER = { NEEDS_USER = {
"description": "Not logged in", "description": "Must be logged in",
"content": None, "content": None,
} }
NEEDS_PERMISSION = { NEEDS_PERMISSION = {
@ -58,10 +58,6 @@ async def get_current_config(
) -> Config: ) -> Config:
""" """
Get the current configuration if it exists. Get the current configuration if it exists.
Status:
- 400: `kiwi-vpn` not installed
""" """
# fail if not configured # fail if not configured
@ -77,10 +73,6 @@ async def get_current_user(
) -> User: ) -> User:
""" """
Get the currently logged-in user if it exists. Get the currently logged-in user if it exists.
Status:
- 403: invalid auth token, or user not found
""" """
# don't use error 404 here - possible user enumeration # don't use error 404 here - possible user enumeration
@ -97,32 +89,23 @@ async def get_current_user(
async def get_user_by_name( async def get_user_by_name(
user_name: str, user_name: str,
) -> User: _: Config = Depends(get_current_config),
) -> User | None:
""" """
Get a user by name. Get a user by name.
Status:
- 404: user not found
""" """
# fail if device doesn't exist return User.get(user_name)
if (user := User.get(user_name)) is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)
return user
async def get_device_by_id( async def get_device_by_id(
device_id: int, device_id: int,
) -> Device: current_config: Config = Depends(get_current_config),
""" ) -> Device | None:
Get a device by ID.
Status: # can't connect to an unconfigured database
if current_config is None:
- 404: device not found raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST)
"""
# fail if device doesn't exist # fail if device doesn't exist
if (device := Device.get(device_id)) is None: if (device := Device.get(device_id)) is None:

View file

@ -4,8 +4,7 @@
from fastapi import APIRouter, Depends, HTTPException, status from fastapi import APIRouter, Depends, HTTPException, status
from ..db import Connection, Device, DeviceCreate, DeviceRead, User from ..db import Device, DeviceCreate, DeviceRead, User
from ..easyrsa import CertificateType, DistinguishedName, EasyRSA
from ._common import (Responses, get_current_user, get_device_by_id, from ._common import (Responses, get_current_user, get_device_by_id,
get_user_by_name) get_user_by_name)
@ -38,6 +37,10 @@ async def add_device(
if not current_user.can_create(Device, owner): if not current_user.can_create(Device, owner):
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN) raise HTTPException(status_code=status.HTTP_403_FORBIDDEN)
# fail if owner doesn't exist
if owner is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)
# create the new device # create the new device
new_device = Device.create( new_device = Device.create(
owner=owner, owner=owner,
@ -76,37 +79,3 @@ async def remove_device(
# delete device # delete device
device.delete() device.delete()
@router.post(
"/{device_id}/csr",
responses={
status.HTTP_200_OK: Responses.OK,
status.HTTP_400_BAD_REQUEST: Responses.NOT_INSTALLED,
status.HTTP_401_UNAUTHORIZED: Responses.NEEDS_USER,
status.HTTP_403_FORBIDDEN: Responses.NEEDS_PERMISSION,
status.HTTP_404_NOT_FOUND: Responses.ENTRY_DOESNT_EXIST,
},
)
async def request_certificate(
current_user: User = Depends(get_current_user),
device: Device = Depends(get_device_by_id),
):
"""
POST ./{device_id}/csr: Request certificate for a device.
"""
# check permission
if not current_user.can_edit(device):
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN)
easy_rsa = EasyRSA()
with Connection.session as db:
db.add(device)
dn = DistinguishedName.build(device)
easy_rsa.issue(
dn=dn,
cert_type=CertificateType.server,
)

View file

@ -4,9 +4,10 @@
from fastapi import APIRouter, Depends, HTTPException, status from fastapi import APIRouter, Depends, HTTPException, status
from ..config import Config
from ..db import User from ..db import User
from ..easyrsa import CertificateType, EasyRSA from ..easyrsa import CertificateType, EasyRSA
from ._common import Responses, get_current_user from ._common import Responses, get_current_config, get_current_user
router = APIRouter(prefix="/service", tags=["service"]) router = APIRouter(prefix="/service", tags=["service"])
@ -16,11 +17,11 @@ router = APIRouter(prefix="/service", tags=["service"])
responses={ responses={
status.HTTP_200_OK: Responses.OK, status.HTTP_200_OK: Responses.OK,
status.HTTP_400_BAD_REQUEST: Responses.NOT_INSTALLED, status.HTTP_400_BAD_REQUEST: Responses.NOT_INSTALLED,
status.HTTP_401_UNAUTHORIZED: Responses.NEEDS_USER,
status.HTTP_403_FORBIDDEN: Responses.NEEDS_PERMISSION, status.HTTP_403_FORBIDDEN: Responses.NEEDS_PERMISSION,
}, },
) )
async def init_pki( async def init_pki(
_: Config = Depends(get_current_config),
current_user: User = Depends(get_current_user), current_user: User = Depends(get_current_user),
) -> None: ) -> None: