Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions homeassistant/components/auth/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ class GrantTokenView(HomeAssistantView):
url = '/auth/token'
name = 'api:auth:token'
requires_auth = False
cors_allowed = True

def __init__(self, retrieve_credentials):
"""Initialize the grant token view."""
Expand Down
12 changes: 6 additions & 6 deletions homeassistant/components/emulated_hue/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,12 @@ def setup(hass, yaml_config):
handler = None
server = None

DescriptionXmlView(config).register(app.router)
HueUsernameView().register(app.router)
HueAllLightsStateView(config).register(app.router)
HueOneLightStateView(config).register(app.router)
HueOneLightChangeView(config).register(app.router)
HueGroupView(config).register(app.router)
DescriptionXmlView(config).register(app, app.router)
HueUsernameView().register(app, app.router)
HueAllLightsStateView(config).register(app, app.router)
HueOneLightStateView(config).register(app, app.router)
HueOneLightChangeView(config).register(app, app.router)
HueGroupView(config).register(app, app.router)

upnp_listener = UPNPResponderThread(
config.host_ip_addr, config.listen_port,
Expand Down
5 changes: 2 additions & 3 deletions homeassistant/components/http/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,7 @@ def __init__(self, hass, api_password,
support_legacy=hass.auth.support_legacy,
api_password=api_password)

if cors_origins:
setup_cors(app, cors_origins)
setup_cors(app, cors_origins)

app['hass'] = hass

Expand Down Expand Up @@ -226,7 +225,7 @@ def register_view(self, view):
'{0} missing required attribute "name"'.format(class_name)
)

view.register(self.app.router)
view.register(self.app, self.app.router)

def register_redirect(self, url, redirect_to):
"""Register a redirect with the server.
Expand Down
14 changes: 14 additions & 0 deletions homeassistant/components/http/cors.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,20 @@ def setup_cors(app, origins):
) for host in origins
})

def allow_cors(route, methods):
"""Allow cors on a route."""
cors.add(route, {
'*': aiohttp_cors.ResourceOptions(
allow_headers=ALLOWED_CORS_HEADERS,
allow_methods=methods,
)
})

app['allow_cors'] = allow_cors

if not origins:
return

async def cors_startup(app):
"""Initialize cors when app starts up."""
cors_added = set()
Expand Down
19 changes: 12 additions & 7 deletions homeassistant/components/http/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ class HomeAssistantView(object):

url = None
extra_urls = []
requires_auth = True # Views inheriting from this class can override this
# Views inheriting from this class can override this
requires_auth = True
cors_allowed = False

# pylint: disable=no-self-use
def json(self, result, status_code=200, headers=None):
Expand All @@ -51,10 +53,11 @@ def json_message(self, message, status_code=200, message_code=None,
data['code'] = message_code
return self.json(data, status_code, headers=headers)

def register(self, router):
def register(self, app, router):
"""Register the view with a router."""
assert self.url is not None, 'No url set for view'
urls = [self.url] + self.extra_urls
routes = []

for method in ('get', 'post', 'delete', 'put'):
handler = getattr(self, method, None)
Expand All @@ -65,13 +68,15 @@ def register(self, router):
handler = request_handler_factory(self, handler)

for url in urls:
router.add_route(method, url, handler)
routes.append(
(method, router.add_route(method, url, handler))
)

# aiohttp_cors does not work with class based views
# self.app.router.add_route('*', self.url, self, name=self.name)
if not self.cors_allowed:
return

# for url in self.extra_urls:
# self.app.router.add_route('*', url, self)
for method, route in routes:
app['allow_cors'](route, [method.upper()])


def request_handler_factory(view, handler):
Expand Down
17 changes: 17 additions & 0 deletions tests/components/auth/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,20 @@ async def test_ws_current_user(hass, hass_ws_client, hass_access_token):
assert user_dict['name'] == user.name
assert user_dict['id'] == user.id
assert user_dict['is_owner'] == user.is_owner


async def test_cors_on_token(hass, aiohttp_client):
"""Test logging in with new user and refreshing tokens."""
client = await async_setup_auth(hass, aiohttp_client)

resp = await client.options('/auth/token', headers={
'origin': 'http://example.com',
'Access-Control-Request-Method': 'POST',
})
assert resp.headers['Access-Control-Allow-Origin'] == 'http://example.com'
assert resp.headers['Access-Control-Allow-Methods'] == 'POST'

resp = await client.post('/auth/token', headers={
'origin': 'http://example.com'
})
assert resp.headers['Access-Control-Allow-Origin'] == 'http://example.com'
8 changes: 4 additions & 4 deletions tests/components/emulated_hue/test_hue_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,10 @@ def hue_client(loop, hass_hue, aiohttp_client):
}
})

HueUsernameView().register(web_app.router)
HueAllLightsStateView(config).register(web_app.router)
HueOneLightStateView(config).register(web_app.router)
HueOneLightChangeView(config).register(web_app.router)
HueUsernameView().register(web_app, web_app.router)
HueAllLightsStateView(config).register(web_app, web_app.router)
HueOneLightStateView(config).register(web_app, web_app.router)
HueOneLightChangeView(config).register(web_app, web_app.router)

return loop.run_until_complete(aiohttp_client(web_app))

Expand Down
4 changes: 2 additions & 2 deletions tests/components/http/test_cors.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@
TRUSTED_ORIGIN = 'https://home-assistant.io'


async def test_cors_middleware_not_loaded_by_default(hass):
async def test_cors_middleware_loaded_by_default(hass):
"""Test accessing to server from banned IP when feature is off."""
with patch('homeassistant.components.http.setup_cors') as mock_setup:
await async_setup_component(hass, 'http', {
'http': {}
})

assert len(mock_setup.mock_calls) == 0
assert len(mock_setup.mock_calls) == 1


async def test_cors_middleware_loaded_from_config(hass):
Expand Down
2 changes: 1 addition & 1 deletion tests/components/http/test_data_validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ async def post(self, request, data):
"""Test method."""
return b''

TestView().register(app.router)
TestView().register(app, app.router)
client = await aiohttp_client(app)
return client

Expand Down