HASwitchPlate / openHASP-custom-component

Home Assistant custom component for openHASP
https://www.openhasp.com
MIT License
51 stars 12 forks source link

Push image not working with SSL cert/key active on HA #81

Open htvekov opened 2 years ago

htvekov commented 2 years ago

openHASP 0.6.3 - HA supervised core-2021.10.5

HA Configuration


homeassistant:
  allowlist_external_dirs:
    - /config
    - /share
    - /tmp

  allowlist_external_urls:
    - "https://www.life360.com/img/user_images/"

  internal_url: http://192.X.X.X:8123
  external_url: https://my_personal.duckdns.org

http:
  ssl_certificate: /ssl/fullchain.pem
  ssl_key: /ssl/privkey.pem

HA direct service call used to test


service: openhasp.push_image
data:
  image: https://my_personal.duckdns.org/local/Mikkel.png
  obj: p5b40
  width: 50
  height: 50
target:
  entity_id: openhasp.wt32_01

Describe the bug

Using duckdns to gain access to HA from external network, causes issues with paths/permissions using openhasp.push_image Using SSL on HA will also disable the possibility to gain local access to HA via http://local_ip_address:port. Only access via https://local_ip_address:port is possible with the expected insecure browser warning. Installing reverse proxy will solve the local access issue with url's, but not necessarily issue with permission/access rights to HA's folders.

Seems like converted image is never recieved. Test picture is tested to be accessible via browser using same url Most likely permission issues with the api/openhasp/serve path. Can't add that specific path to HA's allowlist_external_dirs, as it's not exposed to HA. Also noted that URL pushed to openhasp device is the internal_url from HA configuration. Could also be an issue, as device only will be able to access HA via https URL's (alternatively external duckdns url)

Note: If SSL is deactivated in HA, everything works perfectly without issues at all.

Debug log

2021-12-04 21:20:30 DEBUG (SyncWorker_3) [custom_components.openhasp.image] image_to_rgb565 out_image: /tmp/tmpdghbzkiu 2021-12-04 21:20:30 DEBUG (MainThread) [custom_components.openhasp] Push hasp/wt32_01/command/p5b40.src with http://my.local.ip.address:port/api/openhasp/serve/4ab482c80ba29d55629f5a44f9e1e0f7


wt32-sc01 device log:

21:19:59.876 -> 0KPrompt > MQTT RCV: hasp/wt32_01/command/p5b40.src = http://my.local.ip.address:port/api/openhasp/serve/4ab482c80ba29d55629f5a44f9e1e0f7
21:20:30.415 -> 0KPrompt > ATTR: HTTP result -5
kquinsland commented 2 years ago

I am not sure if HTTPs is supported. Can you repeat this with HTTP only?

A quick google and I think i found the -5 code: https://github.com/espressif/arduino-esp32/blob/master/libraries/HTTPClient/src/HTTPClient.h#L44

fvanroie commented 2 years ago

I pushed an update to 0.7-dev that allows for https in img.src urls. Previously only http:// was accepted and https:// was silently dropped.

Some testing is still required... so feel free to try the latest dev build of the firmware.

htvekov commented 2 years ago

Thanks, @fvanroie

I've tested latest build and got it to work... partially. The plate side is ok now, but some work has to be done in the CC HA environment (path/folders) or the CC code itself.

HA configuration:

homeassistant:
  allowlist_external_dirs:
    - /config
    - /share
    - /tmp

  internal_url: https://XXX.XXX.X.XX:8123
  external_url: https://mypersonalduck.duckdns.org
http:
  ssl_certificate: /ssl/fullchain.pem
  ssl_key: /ssl/privkey.pem

Notice that I've changed HA's internal_url configuration as well to https. So path in mqtt message is absolutely correct (Checked with MQTT Explorer). But plate reports a 404 response though. Also get a 404 response in browser on my local PC as well (unfortunately expected).

Guess HA doesn't really don't want to share that 'internal' non-exposed path via https. Path is not configurable by user and cannot be whitelisted AFAIK. I've not enough knowledge about the topic to come up with a clever solution. Could be that running HA supervised gives extra challenges with the allowed/whitelisted paths ?

But via https i can easily gain browser access eg. to an image stored in a HA whitelisted path/folder. Eg. https://192.xxx.xxx.xxx:8123/local/test_image.jpg

Finalized my tests pushing an already converted image from a whitelisted folder (config/www or local) to plate via HA services:

service: mqtt.publish
data:
  topic: hasp/plates/command/p2b40.src
  payload_template: >
    https://192.XXX.XXX.XXX:8123/local/3c2a249c29fdcde2de1c74d3ad38ac73.dib

With above, image appears on plate šŸ˜€ So issue is about the access rights at HA's end to certain non whitelisted paths/folders. Perhaps the solution is to revise CC a bit and use 'public' HA folders for the final image ? Unless there's a http/ssl/HA folders expert guru here with the perfect solution ? šŸ˜†šŸ™‹ā€ā™‚ļø

exotsk commented 1 year ago

Hi, i have tried install last (and not last) firmware, addon and home assistant, many combinations. but i catch this error alltime. from 192.168.1.1 (router?) which way do I move to solve this problem? HA Supervised with SSL.

2023-01-20 20:27:10.809 ERROR (MainThread) [homeassistant.components.websocket_api.http.connection] [140344930660704] Error handling message: Unknown error (unknown_error) from 192.168.1.1 (Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWe bKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36)
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/components/websocket_api/decorators.py", line 27, in _handle_async_response
await func(hass, connection, msg)
File "/usr/src/homeassistant/homeassistant/components/websocket_api/commands.py", line 646, in handle_execute_script
await script_obj.async_run(msg.get("variables"), context=context)
File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 1524, in async_run
await asyncio.shield(run.async_run())
File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 409, in async_run
await self._async_step(log_exceptions=False)
File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 453, in _async_step
self._handle_exception(
File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 476, in _handle_exception
raise exception
File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 451, in _async_step
await getattr(self, handler)()
File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 684, in _async_call_service_step
await service_task
File "/usr/src/homeassistant/homeassistant/core.py", line 1755, in async_call
task.result()
File "/usr/src/homeassistant/homeassistant/core.py", line 1792, in _execute_service
await cast(Callable[[ServiceCall], Awaitable[None]], handler.job.target)(
File "/usr/src/homeassistant/homeassistant/helpers/entity_component.py", line 213, in handle_service
await service.entity_service_call(
File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 678, in entity_service_call
future.result() # pop exception if have
File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 958, in async_request_call
await coro
File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 715, in _handle_entity_call
await result
File "/config/custom_components/openhasp/init.py", line 616, in async_push_image
f"{get_url(self.hass, allow_external=False)}/api/openhasp/serve/{image_id}"
File "/usr/src/homeassistant/homeassistant/helpers/network.py", line 201, in get_url
raise NoURLAvailableError
homeassistant.helpers.network.NoURLAvailableError

htvekov commented 1 year ago

Haven't really tested lately whether or not openHASP accepts images via https. Have you tested if everything works as expected using http and disabling ssl in HA ?

exotsk commented 1 year ago

In browser all pic is available. i am used ha/local/pic.jpg link, also tried any image from internet (from example for example), had tried use local network http server, with local adress. I have one result. my network have letsencrypt ssl, dynamic ip with DDNS desec.io. for understading situation i had tried to use HassWP (HA for windows) and there i have other error with example data

2023-01-24 14:56:21,579.579 INFO (MainThread) [homeassistant.helpers.script.websocket_api_script] websocket_api script: Running websocket_api script 2023-01-24 14:56:21,579.579 INFO (MainThread) [homeassistant.helpers.script.websocket_api_script] websocket_api script: Executing step call service 2023-01-24 14:56:23,321.321 ERROR (MainThread) [aiohttp.server] Unhandled exception Traceback (most recent call last): File "D:\HassWP\python-3.9.10.amd64\lib\site-packages\aiohttp\web_protocol.py", line 514, in start resp, reset = await task File "D:\HassWP\python-3.9.10.amd64\lib\site-packages\aiohttp\web_protocol.py", line 460, in _handle_request reset = await self.finish_response(request, resp, start_time) File "D:\HassWP\python-3.9.10.amd64\lib\site-packages\aiohttp\web_protocol.py", line 613, in finish_response await prepare_meth(request) File "D:\HassWP\python-3.9.10.amd64\lib\site-packages\aiohttp\web_fileresponse.py", line 279, in prepare fobj = await loop.run_in_executor(None, filepath.open, "rb") File "D:\HassWP\python-3.9.10.amd64\lib\concurrent\futures\thread.py", line 58, in run result = self.fn(*self.args, **self.kwargs) File "D:\HassWP\python-3.9.10.amd64\lib\pathlib.py", line 1252, in open return io.open(self, mode, buffering, encoding, errors, newline, File "D:\HassWP\python-3.9.10.amd64\lib\pathlib.py", line 1120, in _opener return self._accessor.open(self, flags, mode) PermissionError: [Errno 13] Permission denied: 'C:\Users\name\AppData\Local\Temp\tmp1wukuwzu'

this feature very important for use, especially on big screens, and i hope, can make it work

exotsk commented 1 year ago

Unknown error disappeared with ssl turned off, but I get the following. 2023-01-30 11:49:29.809 ERROR (MainThread) [aiohttp.server] Error handling request
Traceback (most recent call last):
File "/usr/local/lib/python3.10/site-packages/aiohttp/web_protocol.py", line 334, in data_received
messages, upgraded, tail = self._request_parser.feed_data(data)
File "aiohttp/_http_parser.pyx", line 551, in aiohttp._http_parser.HttpParser.feed_data
aiohttp.http_exceptions.BadStatusLine: 400, message="Bad status line 'Invalid method encountered'"
2023-01-30 11:49:34.925 ERROR (MainThread) [aiohttp.server] Error handling request
Traceback (most recent call last):
File "/usr/local/lib/python3.10/site-packages/aiohttp/web_protocol.py", line 334, in data_received
messages, upgraded, tail = self._request_parser.feed_data(data)
File "aiohttp/_http_parser.pyx", line 551, in aiohttp._http_parser.HttpParser.feed_data
aiohttp.http_exceptions.BadStatusLine: 400, message="Bad status line 'Invalid method encountered'"

if ssl is enabled and configured as here. I get an error from 192.168.1.1 if I work on the XA external link, and from the local machine 192.168.1.99 if I work on the XA internal link https ://192.168.1.110: 8123 at this log location. 2023-01-20 20:27:10.809

MainThread [homeassistant.components.websocket_api.http.connection] [140344930660704] Error Message: Unknown Error (unknown_error) from 192.168.1.1

When i give URL from local http server with jpg image by command through MQTT (src), I receive NoData in place of the picture, in other cases it does not change in any way. image image

exotsk commented 1 year ago

This error log is caught by XA for windows initially without ssl. Errors with access rights from temp directory are visible here.

2023-01-30 12:11:37,728.728 INFO (MainThread) [homeassistant.helpers.script.websocket_api_script] websocket_api script: Running websocket_api script 2023-01-30 12:11:37,728.728 INFO (MainThread) [homeassistant.helpers.script.websocket_api_script] websocket_api script: Executing step call service 2023-01-30 12:11:53,318.318 INFO (MainThread) [homeassistant.helpers.script.websocket_api_script] websocket_api script: Running websocket_api script 2023-01-30 12:11:53,318.318 INFO (MainThread) [homeassistant.helpers.script.websocket_api_script] websocket_api script: Executing step call service 2023-01-30 12:11:53,404.404 ERROR (MainThread) [aiohttp.server] Unhandled exception Traceback (most recent call last): File "D:\HassWP\python-3.9.10.amd64\lib\site-packages\aiohttp\web_protocol.py", line 514, in start resp, reset = await task File "D:\HassWP\python-3.9.10.amd64\lib\site-packages\aiohttp\web_protocol.py", line 460, in _handle_request reset = await self.finish_response(request, resp, start_time) File "D:\HassWP\python-3.9.10.amd64\lib\site-packages\aiohttp\web_protocol.py", line 613, in finish_response await prepare_meth(request) File "D:\HassWP\python-3.9.10.amd64\lib\site-packages\aiohttp\web_fileresponse.py", line 279, in prepare fobj = await loop.run_in_executor(None, filepath.open, "rb") File "D:\HassWP\python-3.9.10.amd64\lib\concurrent\futures\thread.py", line 58, in run result = self.fn(*self.args, **self.kwargs) File "D:\HassWP\python-3.9.10.amd64\lib\pathlib.py", line 1252, in open return io.open(self, mode, buffering, encoding, errors, newline, File "D:\HassWP\python-3.9.10.amd64\lib\pathlib.py", line 1120, in _opener return self._accessor.open(self, flags, mode) PermissionError: [Errno 13] Permission denied: 'C:\Users\exo\AppData\Local\Temp\tmpxtu63qje'

dgomes commented 1 year ago

Well this is not going to work properly on windows because we use UNIX temporary files to generate the images.

@htvekov when using SSL there are 2 possible configuration (SSL handled by HA or SSL handled by a Reverse Proxy). That means that you must tell HA your configuration setup using internal_url and external_url in order for CC to known which is what. For security reasons CC always prefers internal_url paths...

htvekov commented 1 year ago

I did some quick SSL tests last night, when I was playing with image config anyway šŸ˜‰

Didn't save any logs, but I can redo test later if needed. I use DuckDNS only (no reverse proxy). As far as I understood from last time we talked about this SSL issue, it all boils down to HA not accepting DuckDNS access as the cert is not valid. I get cert warnings in the HA log.

If adding https address or my DuckDNS path in HA's internal_url outbound mqtt message to plate is correct, but plate is not allowed/can't find the file and returns a 404 HTTP error.

Using a browser I can access the file entering the exact same path (copy/paste from openHASP log)

openHASP fw still accepts inbound https messages. I've retested with a dib file i had stored locally and i can without issues push that direct src mqtt message

dgomes commented 1 year ago

If HA is configured to handle SSL (https://www.home-assistant.io/integrations/http/#ssl_certificate) then you must have httpS in the internal_url address.

Please activate CC debug mode and provide logs

htvekov commented 1 year ago

If HA is configured to handle SSL (https://www.home-assistant.io/integrations/http/#ssl_certificate) then you must have httpS in the internal_url address.

Please activate CC debug mode and provide logs

I went through various scenarios and actually got SSL working with one specific configuration šŸŽ‰šŸ™‚

For SSL to work here using 'standard' DuckDNS following settings must be done:

Image path for push_image service MUST start with: image: https://myduckdns.duckdns.org.....

internal_url setting in HA MUST be the duckDNS url:

internal_url: https://myduckdns.duckdns.org
external_url: https://myduckdns.duckdns.org

I guess that using above will direct all traffic between HA and external components through DuckDNS (not really the best solution)

Debug log clips from CC in HA + openHASP logs attached. Four different scenarios tested.

HA has some SSL protocol issues if two images are send within a few seconds (in my case images are identical)

ssl_openhasp_log.txt

dgomes commented 1 year ago

1st snippet:

CC can't access media_player content (CC validated the SSL certificate and did not match IP/hostname)

2nd snippet:

CC did get the image and made available... then something wrong with your automation...

3rd snippet:

Likely trying to serve http over https...

4th snippet:

Again... SSL mismatch.

Conclusions: you are running SSL in HA and therefore you get all sorts of SSL mismatches... My advise: move SSL out of HA and leave http:// as internal_url

htvekov commented 1 year ago

Well, I guess you're absolutely right that SSL in HA is not an ideal solution. Either have SSL outside of HA or use HA Companion app if you just want access to HA from outside your own network. Thank you for your input on this šŸ‘

Anyway, both CC and openHASP fw supports SSL. I've just confirmed that with my tests. Don't know if you got the snippets mixed up or I just misunderstood what 3rd snippet is, as the 3rd snippet actually is the working solution šŸ˜‰šŸ˜

dgomes commented 1 year ago

In the 3rd snippet you are not making use of internal_url... It's working, but all your internal traffic is going around the internet... (not a good idea)

htvekov commented 1 year ago

In the 3rd snippet you are not making use of internal_url... It's working, but all your internal traffic is going around the internet... (not a good idea)

Ok. Then I understood what you meant šŸ™‚ Yep. I fully agree. Even though it's working, it's not a viable solution.

I guess a reverse proxy configuration (nginx or similar) would work as expected. But I have close to zero network knowledge. So I won't spend time going down that path. I'll support the HA community instead and go with the Companion app.

exotsk commented 1 year ago

Please tell me if I use the local http server and use the src command via mqtt (it is used by the push image service from ha?) How to send an image to the board correctly? are there size or format restrictions? I don't use duckdns if it's important to work over ssl.

jazzmonger commented 10 months ago

Does this lend any clues?

Logger: homeassistant.components.automation.openhasp_push_image_to_plate
Source: helpers/script.py:468
Integration: Automation ([documentation](https://www.home-assistant.io/integrations/automation), [issues](https://github.com/home-assistant/core/issues?q=is%3Aissue+is%3Aopen+label%3A%22integration%3A+automation%22))
First occurred: 9:00:54 AM (2 occurrences)
Last logged: 9:02:35 AM

HASP push Media image to Kitchen plate: Error executing script. Unexpected error for call_service at pos 1: module 'PIL.Image' has no attribute 'ANTIALIAS'
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 468, in _async_step
    await getattr(self, handler)()
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 704, in _async_call_service_step
    response_data = await self._async_run_long_action(
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 666, in _async_run_long_action
    return long_task.result()
           ^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/core.py", line 2035, in async_call
    response_data = await coro
                    ^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/core.py", line 2072, in _execute_service
    return await target(service_call)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/entity_component.py", line 235, in handle_service
    return await service.entity_service_call(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 876, in entity_service_call
    response_data = await _handle_entity_call(
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 948, in _handle_entity_call
    result = await task
             ^^^^^^^^^^
  File "/config/custom_components/openhasp/__init__.py", line 607, in async_push_image
    rgb_image = await self.hass.async_add_executor_job(
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/openhasp/image.py", line 35, in image_to_rgb565
    im.thumbnail((height, width), Image.ANTIALIAS)
                                  ^^^^^^^^^^^^^^^
AttributeError: module 'PIL.Image' has no attribute 'ANTIALIAS'
Suschibomber commented 1 month ago

Does this still dosen't work?

xNUTx commented 1 month ago

https://github.com/HASwitchPlate/openHASP-custom-component/pull/144 will be a solution to this.

fvanroie commented 3 weeks ago

144 is included in 0.7.5 now.