Skip to content

Commit dff8e52

Browse files
authored
Use API token authentiation in traccar_server (#155297)
1 parent dbfa0aa commit dff8e52

File tree

9 files changed

+52
-55
lines changed

9 files changed

+52
-55
lines changed

homeassistant/components/traccar/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@
77
"documentation": "https://www.home-assistant.io/integrations/traccar",
88
"iot_class": "cloud_push",
99
"loggers": ["pytraccar"],
10-
"requirements": ["pytraccar==2.1.1", "stringcase==1.2.0"]
10+
"requirements": ["pytraccar==3.0.0", "stringcase==1.2.0"]
1111
}

homeassistant/components/traccar_server/__init__.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
from homeassistant.config_entries import ConfigEntry
1111
from homeassistant.const import (
12+
CONF_API_TOKEN,
1213
CONF_HOST,
1314
CONF_PASSWORD,
1415
CONF_PORT,
@@ -18,6 +19,7 @@
1819
Platform,
1920
)
2021
from homeassistant.core import HomeAssistant
22+
from homeassistant.exceptions import ConfigEntryAuthFailed
2123
from homeassistant.helpers.aiohttp_client import async_create_clientsession
2224
from homeassistant.helpers.event import async_track_time_interval
2325

@@ -33,6 +35,11 @@
3335

3436
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
3537
"""Set up Traccar Server from a config entry."""
38+
if CONF_API_TOKEN not in entry.data:
39+
raise ConfigEntryAuthFailed(
40+
translation_domain=DOMAIN,
41+
translation_key="migrate_to_api_token",
42+
)
3643
client_session = async_create_clientsession(
3744
hass,
3845
cookie_jar=CookieJar(
@@ -46,8 +53,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
4653
client_session=client_session,
4754
host=entry.data[CONF_HOST],
4855
port=entry.data[CONF_PORT],
49-
username=entry.data[CONF_USERNAME],
50-
password=entry.data[CONF_PASSWORD],
56+
token=entry.data[CONF_API_TOKEN],
5157
ssl=entry.data[CONF_SSL],
5258
verify_ssl=entry.data[CONF_VERIFY_SSL],
5359
),
@@ -90,3 +96,15 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
9096
async def async_reload_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
9197
"""Handle an options update."""
9298
await hass.config_entries.async_reload(entry.entry_id)
99+
100+
101+
async def async_migrate_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
102+
"""Migrate old entry."""
103+
104+
if entry.version < 2:
105+
# Version 2: Remove username and password, only keep API token
106+
data = dict(entry.data)
107+
data.pop(CONF_USERNAME, None)
108+
data.pop(CONF_PASSWORD, None)
109+
hass.config_entries.async_update_entry(entry, data=data, version=2)
110+
return True

homeassistant/components/traccar_server/config_flow.py

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,10 @@
1616
from homeassistant import config_entries
1717
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
1818
from homeassistant.const import (
19+
CONF_API_TOKEN,
1920
CONF_HOST,
20-
CONF_PASSWORD,
2121
CONF_PORT,
2222
CONF_SSL,
23-
CONF_USERNAME,
2423
CONF_VERIFY_SSL,
2524
)
2625
from homeassistant.core import callback
@@ -61,10 +60,7 @@
6160
vol.Optional(CONF_PORT, default="8082"): TextSelector(
6261
TextSelectorConfig(type=TextSelectorType.TEXT)
6362
),
64-
vol.Required(CONF_USERNAME): TextSelector(
65-
TextSelectorConfig(type=TextSelectorType.EMAIL)
66-
),
67-
vol.Required(CONF_PASSWORD): TextSelector(
63+
vol.Required(CONF_API_TOKEN): TextSelector(
6864
TextSelectorConfig(type=TextSelectorType.PASSWORD)
6965
),
7066
vol.Optional(CONF_SSL, default=False): BooleanSelector(BooleanSelectorConfig()),
@@ -120,16 +116,17 @@
120116
class TraccarServerConfigFlow(ConfigFlow, domain=DOMAIN):
121117
"""Handle a config flow for Traccar Server."""
122118

119+
VERSION = 2
120+
123121
async def _get_server_info(self, user_input: dict[str, Any]) -> ServerModel:
124122
"""Get server info."""
125123
client = ApiClient(
126124
client_session=async_get_clientsession(self.hass),
127125
host=user_input[CONF_HOST],
128126
port=user_input[CONF_PORT],
129-
username=user_input[CONF_USERNAME],
130-
password=user_input[CONF_PASSWORD],
131127
ssl=user_input[CONF_SSL],
132128
verify_ssl=user_input[CONF_VERIFY_SSL],
129+
token=user_input[CONF_API_TOKEN],
133130
)
134131
return await client.get_server()
135132

@@ -201,19 +198,11 @@ async def async_step_reauth_confirm(
201198
reauth_entry,
202199
data_updates=user_input,
203200
)
204-
username = (
205-
user_input[CONF_USERNAME]
206-
if user_input
207-
else reauth_entry.data[CONF_USERNAME]
208-
)
209201
return self.async_show_form(
210202
step_id="reauth_confirm",
211203
data_schema=vol.Schema(
212204
{
213-
vol.Required(CONF_USERNAME, default=username): TextSelector(
214-
TextSelectorConfig(type=TextSelectorType.EMAIL)
215-
),
216-
vol.Required(CONF_PASSWORD): TextSelector(
205+
vol.Required(CONF_API_TOKEN): TextSelector(
217206
TextSelectorConfig(type=TextSelectorType.PASSWORD)
218207
),
219208
}

homeassistant/components/traccar_server/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@
55
"config_flow": true,
66
"documentation": "https://www.home-assistant.io/integrations/traccar_server",
77
"iot_class": "local_push",
8-
"requirements": ["pytraccar==2.1.1"]
8+
"requirements": ["pytraccar==3.0.0"]
99
}

homeassistant/components/traccar_server/strings.json

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,21 @@
1212
"step": {
1313
"reauth_confirm": {
1414
"data": {
15-
"password": "[%key:common::config_flow::data::password%]",
16-
"username": "[%key:common::config_flow::data::username%]"
15+
"api_token": "[%key:common::config_flow::data::api_token%]"
1716
},
1817
"description": "The authentication credentials for {host}:{port} need to be updated."
1918
},
2019
"user": {
2120
"data": {
21+
"api_token": "[%key:common::config_flow::data::api_token%]",
2222
"host": "[%key:common::config_flow::data::host%]",
23-
"password": "[%key:common::config_flow::data::password%]",
2423
"port": "[%key:common::config_flow::data::port%]",
2524
"ssl": "[%key:common::config_flow::data::ssl%]",
26-
"username": "[%key:common::config_flow::data::username%]",
2725
"verify_ssl": "[%key:common::config_flow::data::verify_ssl%]"
2826
},
2927
"data_description": {
30-
"host": "The hostname or IP address of your Traccar Server",
31-
"username": "The username (email) you use to log in to your Traccar Server"
28+
"api_token": "The API token generated from your account on your Traccar Server",
29+
"host": "The hostname or IP address of your Traccar Server"
3230
}
3331
}
3432
}
@@ -62,6 +60,11 @@
6260
}
6361
}
6462
},
63+
"exceptions": {
64+
"migrate_to_api_token": {
65+
"message": "To continue using Traccar Server, you need to migrate to API token based authentication."
66+
}
67+
},
6568
"options": {
6669
"step": {
6770
"init": {

requirements_all.txt

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

requirements_test_all.txt

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/components/traccar_server/conftest.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,10 @@
1414
DOMAIN,
1515
)
1616
from homeassistant.const import (
17+
CONF_API_TOKEN,
1718
CONF_HOST,
18-
CONF_PASSWORD,
1919
CONF_PORT,
2020
CONF_SSL,
21-
CONF_USERNAME,
2221
CONF_VERIFY_SSL,
2322
)
2423

@@ -74,8 +73,7 @@ def mock_config_entry() -> MockConfigEntry:
7473
data={
7574
CONF_HOST: "1.1.1.1",
7675
CONF_PORT: "8082",
77-
CONF_USERNAME: "[email protected]",
78-
CONF_PASSWORD: "ThisIsNotThePasswordYouAreL00kingFor",
76+
CONF_API_TOKEN: "ThisIsNotThePasswordYouAreL00kingFor",
7977
CONF_SSL: False,
8078
CONF_VERIFY_SSL: True,
8179
},

tests/components/traccar_server/test_config_flow.py

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,10 @@
1616
)
1717
from homeassistant.config_entries import ConfigEntryState
1818
from homeassistant.const import (
19+
CONF_API_TOKEN,
1920
CONF_HOST,
20-
CONF_PASSWORD,
2121
CONF_PORT,
2222
CONF_SSL,
23-
CONF_USERNAME,
2423
CONF_VERIFY_SSL,
2524
)
2625
from homeassistant.core import HomeAssistant
@@ -44,8 +43,7 @@ async def test_form(
4443
result["flow_id"],
4544
{
4645
CONF_HOST: "1.1.1.1",
47-
CONF_USERNAME: "test-username",
48-
CONF_PASSWORD: "test-password",
46+
CONF_API_TOKEN: "test-token",
4947
},
5048
)
5149
await hass.async_block_till_done()
@@ -55,8 +53,7 @@ async def test_form(
5553
assert result["data"] == {
5654
CONF_HOST: "1.1.1.1",
5755
CONF_PORT: "8082",
58-
CONF_USERNAME: "test-username",
59-
CONF_PASSWORD: "test-password",
56+
CONF_API_TOKEN: "test-token",
6057
CONF_SSL: False,
6158
CONF_VERIFY_SSL: True,
6259
}
@@ -87,8 +84,7 @@ async def test_form_cannot_connect(
8784
result["flow_id"],
8885
{
8986
CONF_HOST: "1.1.1.1",
90-
CONF_USERNAME: "test-username",
91-
CONF_PASSWORD: "test-password",
87+
CONF_API_TOKEN: "test-token",
9288
},
9389
)
9490

@@ -101,8 +97,7 @@ async def test_form_cannot_connect(
10197
result["flow_id"],
10298
{
10399
CONF_HOST: "1.1.1.1",
104-
CONF_USERNAME: "test-username",
105-
CONF_PASSWORD: "test-password",
100+
CONF_API_TOKEN: "test-token",
106101
},
107102
)
108103
await hass.async_block_till_done()
@@ -112,8 +107,7 @@ async def test_form_cannot_connect(
112107
assert result["data"] == {
113108
CONF_HOST: "1.1.1.1",
114109
CONF_PORT: "8082",
115-
CONF_USERNAME: "test-username",
116-
CONF_PASSWORD: "test-password",
110+
CONF_API_TOKEN: "test-token",
117111
CONF_SSL: False,
118112
CONF_VERIFY_SSL: True,
119113
}
@@ -168,8 +162,7 @@ async def test_abort_already_configured(
168162
{
169163
CONF_HOST: "1.1.1.1",
170164
CONF_PORT: "8082",
171-
CONF_USERNAME: "test-username",
172-
CONF_PASSWORD: "test-password",
165+
CONF_API_TOKEN: "test-token",
173166
},
174167
)
175168

@@ -201,8 +194,7 @@ async def test_reauth_flow(
201194
result = await hass.config_entries.flow.async_configure(
202195
result["flow_id"],
203196
{
204-
CONF_USERNAME: "new-username",
205-
CONF_PASSWORD: "new-password",
197+
CONF_API_TOKEN: "new-token",
206198
},
207199
)
208200
await hass.async_block_till_done()
@@ -211,8 +203,7 @@ async def test_reauth_flow(
211203
assert result["reason"] == "reauth_successful"
212204

213205
# Verify the config entry was updated
214-
assert mock_config_entry.data[CONF_USERNAME] == "new-username"
215-
assert mock_config_entry.data[CONF_PASSWORD] == "new-password"
206+
assert mock_config_entry.data[CONF_API_TOKEN] == "new-token"
216207

217208

218209
@pytest.mark.parametrize(
@@ -248,8 +239,7 @@ async def test_reauth_flow_errors(
248239
result = await hass.config_entries.flow.async_configure(
249240
result["flow_id"],
250241
{
251-
CONF_USERNAME: "new-username",
252-
CONF_PASSWORD: "new-password",
242+
CONF_API_TOKEN: "new-token",
253243
},
254244
)
255245

@@ -262,8 +252,7 @@ async def test_reauth_flow_errors(
262252
result = await hass.config_entries.flow.async_configure(
263253
result["flow_id"],
264254
{
265-
CONF_USERNAME: "new-username",
266-
CONF_PASSWORD: "new-password",
255+
CONF_API_TOKEN: "new-token",
267256
},
268257
)
269258
await hass.async_block_till_done()

0 commit comments

Comments
 (0)