Skip to content

Commit

Permalink
feat(system-server): add /system/oem_mode/upload_splash endpoint to c…
Browse files Browse the repository at this point in the history
…hange the userspace boot screen. (#14865)
  • Loading branch information
vegano1 authored and Carlos-fernandez committed May 20, 2024
1 parent 39437a3 commit 63195e5
Show file tree
Hide file tree
Showing 7 changed files with 196 additions and 5 deletions.
1 change: 1 addition & 0 deletions system-server/Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pydantic = "==1.10.12"
importlib-metadata = ">=4.13.0,<5"
sqlalchemy = "==1.4.51"
pyjwt = "==2.6.0"
filetype = "==1.2.0"
systemd-python = { version = "==234", markers="sys_platform == 'linux'" }
server-utils = {editable = true, path = "./../server-utils"}
system_server = {path = ".", editable = true}
Expand Down
14 changes: 11 additions & 3 deletions system-server/Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

97 changes: 96 additions & 1 deletion system-server/system_server/system/oem_mode/router.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
"""Router for /system/register endpoint."""

from fastapi import APIRouter, Depends, status, Response
import os
import filetype # type: ignore[import-untyped]
from fastapi import (
APIRouter,
Depends,
status,
Response,
UploadFile,
File,
HTTPException,
)

from .models import EnableOEMMode
from ...settings import SystemServerSettings, get_settings, save_settings

Expand Down Expand Up @@ -35,3 +46,87 @@ async def enable_oem_mode_endpoint(
except Exception:
response.status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
return response


@oem_mode_router.post(
"/system/oem_mode/upload_splash",
summary="Upload an image to be used as the boot up splash screen.",
responses={
status.HTTP_201_CREATED: {"message": "OEM Mode splash screen uploaded"},
status.HTTP_400_BAD_REQUEST: {"message": "OEM Mode splash screen not set"},
status.HTTP_413_REQUEST_ENTITY_TOO_LARGE: {
"message": "File is larger than 5mb"
},
status.HTTP_415_UNSUPPORTED_MEDIA_TYPE: {"message": "Invalid file type"},
status.HTTP_500_INTERNAL_SERVER_ERROR: {
"message": "OEM Mode splash unhandled exception."
},
},
)
async def upload_splash_image(
response: Response,
file: UploadFile = File(...),
settings: SystemServerSettings = Depends(get_settings),
) -> Response:
"""Router for /system/oem_mode/upload_splash endpoint."""
# Make sure oem mode is enabled before this request
if not settings.oem_mode_enabled:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="OEM Mode needs to be enabled to upload splash image.",
)

# Get the file info
file_info = filetype.guess(file.file)
if file_info is None:
raise HTTPException(
status_code=status.HTTP_415_UNSUPPORTED_MEDIA_TYPE,
detail="Unable to determine file type",
)

# Only accept PNG files
accepted_file_types = ["image/png", "png"]
content_type = file_info.extension.lower()
if (
file.content_type not in accepted_file_types
or content_type not in accepted_file_types
):
raise HTTPException(
status_code=status.HTTP_415_UNSUPPORTED_MEDIA_TYPE,
detail="Unsupported file type",
)

file_size = 0
for chunk in file.file:
file_size += len(chunk)
if file_size > 5 * 1024 * 1024: # 5MB
raise HTTPException(
status_code=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE,
detail="File is larger than 5mb.",
)

# TODO: Validate image dimensions

# return the pointer back to the starting point so that the next read starts from the starting point
await file.seek(0)

try:
# Remove the old image if exists
if settings.oem_mode_splash_custom:
os.unlink(settings.oem_mode_splash_custom)

# file is valid, save to final location
filepath = f"{settings.persistence_directory}/{file.filename}"
with open(filepath, "wb+") as f:
f.write(file.file.read())

# store the file location to settings and save the dotenv
settings.oem_mode_splash_custom = filepath
success = save_settings(settings)
response.status_code = (
status.HTTP_201_CREATED if success else status.HTTP_400_BAD_REQUEST
)
except Exception:
response.status_code = status.HTTP_500_INTERNAL_SERVER_ERROR

return response
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
89 changes: 88 additions & 1 deletion system-server/tests/integration/test_oem_mode.tavern.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
test_name: PUT Enable OEM Mode
test_name: Test enable/disable OEM Mode
marks:
- usefixtures:
- run_server
Expand Down Expand Up @@ -34,4 +34,91 @@ stages:
content-type: application/json
response:
status_code: 422
---
test_name: Upload, and validate a good image for OEM Mode

marks:
- usefixtures:
- run_server
stages:
- name: Enable OEM Mode
request:
url: "{host:s}:{port:d}/system/oem_mode/enable"
method: PUT
json:
"enable": true
- name: Upload PNG Image
request: &upload_splash_first
url: "{host:s}:{port:d}/system/oem_mode/upload_splash"
method: POST
files:
file: 'tests/integration/resources/oem_mode_custom.png'
response:
status_code: 201

---
test_name: Dont process upload_splash request if oem mode is disabled

marks:
- usefixtures:
- run_server

stages:
- name: Disable OEM Mode
request:
url: "{host:s}:{port:d}/system/oem_mode/enable"
method: PUT
json:
"enable": false
- name: Upload PNG Image
request:
url: "{host:s}:{port:d}/system/oem_mode/upload_splash"
method: POST
files:
file: 'tests/integration/resources/oem_mode_custom.png'
response:
status_code: 403
- name: Enable OEM Mode
request:
url: "{host:s}:{port:d}/system/oem_mode/enable"
method: PUT
json:
"enable": true
- name: Upload PNG Image
request:
url: "{host:s}:{port:d}/system/oem_mode/upload_splash"
method: POST
files:
file: 'tests/integration/resources/oem_mode_custom.png'
response:
status_code: 201
---
test_name: Validate the image before processing

marks:
- usefixtures:
- run_server

stages:
- name: Enable OEM Mode
request:
url: "{host:s}:{port:d}/system/oem_mode/enable"
method: PUT
json:
"enable": true
- name: Upload non-PNG Image
request:
url: "{host:s}:{port:d}/system/oem_mode/upload_splash"
method: POST
files:
file: 'tests/integration/resources/oem_mode_wrong_image_type.jpeg'
response:
status_code: 415
- name: Upload a PNG Image
request:
url: "{host:s}:{port:d}/system/oem_mode/upload_splash"
method: POST
files:
file: 'tests/integration/resources/oem_mode_custom.png'
response:
status_code: 201

0 comments on commit 63195e5

Please sign in to comment.