Skip to content

Display policy: "Timeout duration" text field has no client-side format validation #41

Description

@HummelsTech

Summary

The Display settings step's "Timeout duration" field (screen_timeout in config_flow.py, DISPLAY_SCHEMA) is a free-text TextSelector with no format validation. Applying a policy with a malformed value fails with a raw googleapiclient.errors.HttpError traceback instead of a friendly form error.

Reproduction

  1. Open the integration's options flow → Display settings.
  2. Enter a value in "Timeout duration" that doesn't match Google's protobuf Duration string format (e.g. a bare 0 instead of 0s).
  3. Apply the policy.

Result

googleapiclient.errors.HttpError: <HttpError 400 ...
"Invalid value at 'policy.display_settings.screen_timeout_settings.screen_timeout' ...
Illegal duration format; duration must end with 's'">

Traceback: config_flow.py async_step_apply_policyapi.py async_set_policy_set_policygoogleapiclient http.execute().

Root cause

I traced the field end-to-end and confirmed there is no string transformation anywhere in the integration — async_step_display does self._options.update(user_input) verbatim, build_policy_from_options does timeout["screenTimeout"] = opts["screen_timeout"] verbatim, and api.py forwards the policy body unchanged to the Google Android Management API. So whatever string is typed into the field is sent to Google exactly as-is, with no local validation first. If the field doesn't end in s (or otherwise doesn't match Google's Duration string format), the failure only surfaces as an unhandled 400 from Google, logged via _LOGGER.exception("Failed to apply policy '%s'", policy_id) and surfaced to the user as a generic apply_failed form error — the underlying "must end with 's'" detail isn't shown in the UI at all.

The field's data_description hint text ("Duration string, e.g. 220s, 60s, 0s (never)") only appears as help text next to the field — it's not a placeholder/prefill, so it's easy to type a bare number by mistake and only find out via a stack trace in the HA log.

Suggested fix

Add a vol.Match (or equivalent) validator to the screen_timeout field in DISPLAY_SCHEMA, e.g.:

vol.Optional("screen_timeout", default="220s"): vol.All(_text(), vol.Match(r"^\d+(\.\d+)?s$")),

so a malformed duration is rejected locally with a clear form error instead of round-tripping to Google's API first.

Happy to send a PR for this if useful — just wanted to confirm the root cause here first.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions