mlock: cache valid tokens

This commit is contained in:
neri 2024-07-20 04:25:03 +02:00
parent 8007a86bbf
commit ce18b83ece
2 changed files with 164 additions and 83 deletions

9
mlock-common.h Normal file
View File

@ -0,0 +1,9 @@
#include <algorithm>
#include <string>
int decode_token(std::string token) {
// strip dashes from token
token.erase(std::remove(token.begin(), token.end(), '-'), token.end());
// parse token from hex to unsigned int
return static_cast<unsigned int>(std::stoll(token, nullptr, 16));
}

View File

@ -13,8 +13,8 @@ substitutions:
###### nothing to change below this line ###### ###### nothing to change below this line ######
esphome: esphome:
name: mlock-${name_of_board} name: mlock-${name_of_board}
platform: ESP8266 includes:
board: d1_mini - mlock-common.h
on_boot: on_boot:
- priority: 300 - priority: 300
then: then:
@ -29,6 +29,10 @@ esphome:
else: else:
- light.addressable_set: { id: status_led, red: 100%, green: 0%, blue: 0% } - light.addressable_set: { id: status_led, red: 100%, green: 0%, blue: 0% }
esp8266:
board: d1_mini
restore_from_flash: true # max 96 bytes
# Enable logging # Enable logging
logger: logger:
@ -67,27 +71,48 @@ http_request:
id: http_request_data id: http_request_data
globals: globals:
- id: my_token - id: vault_api_token
type: std::string type: std::string
restore_value: no restore_value: no
- id: my_tag - id: rfid_tag
type: std::string type: std::string
restore_value: no restore_value: no
- id: may_switch_output - id: access_allowed
type: int type: bool
restore_value: no restore_value: no
initial_value: 'false'
- id: access_cache
type: unsigned int[24]
restore_value: yes
initial_value: '{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}'
rc522_spi: script:
cs_pin: GPIO15 - id: check_access
on_tag: then:
- if:
condition:
lambda: |-
int rfid_value = decode_token(id(rfid_tag));
for (int i = 0; i < 24; i++) {
if (id(access_cache)[i] == rfid_value) {
return true;
}
}
return false;
then:
- script.execute: toggle_switch
- script.wait: toggle_switch
- if: # return LED to switch state before
condition:
switch.is_on: mlock_${name_of_board}_switch
then:
- light.addressable_set: { id: status_led, red: 0%, green: 100%, blue: 0% }
else:
- light.addressable_set: { id: status_led, red: 100%, green: 0%, blue: 0% }
else:
- script.execute: fetch_token_vault
- id: fetch_token_vault
then: then:
- light.addressable_set: { id: status_led, red: 100%, green: 60%, blue: 0% }
# small delay so the light can update its color
- delay: 15ms
# store the tag id into global variable
- lambda: |-
id(my_tag) = x;
id(may_switch_output) = 0;
# login to vault with role_id to fetch short lived token # login to vault with role_id to fetch short lived token
- http_request.post: - http_request.post:
url: https://vault.ctdo.de/v1/auth/approle/login url: https://vault.ctdo.de/v1/auth/approle/login
@ -98,79 +123,118 @@ rc522_spi:
role_id: $vault_role_id role_id: $vault_role_id
secret_id: $vault_secret_id secret_id: $vault_secret_id
on_response: on_response:
# fetch token from response, store into my_token # fetch token from response, store into vault_api_token
then: then:
- lambda: |- - lambda: |-
json::parse_json(id(http_request_data).get_string(), [](JsonObject root) { json::parse_json(id(http_request_data).get_string(), [](JsonObject root) {
id(my_token) = (const char*) root["auth"]["client_token"]; id(vault_api_token) = (const char*) root["auth"]["client_token"];
}); });
# use the token to get json of scanned tag from vault - script.execute: check_access_vault
- http_request.get: - id: check_access_vault
url: !lambda |- then:
return ((std::string) "https://vault.ctdo.de/v1/maschinenlock/" + id(my_tag)); - lambda: |-
verify_ssl: false id(access_allowed) = false;
headers: - http_request.get:
X-Vault-Token: !lambda return id(my_token).c_str(); url: !lambda |-
on_response: return ((std::string) "https://vault.ctdo.de/v1/maschinenlock/" + id(rfid_tag));
then: verify_ssl: false
- if: headers:
condition: X-Vault-Token: !lambda return id(vault_api_token).c_str();
lambda: 'return status_code == 200;' on_response:
then: # when found, check if machine is allowed, turn on output or blink LED red then:
- lambda: |- - if:
json::parse_json(id(http_request_data).get_string(), [](JsonObject root) { condition:
id(may_switch_output) = root["data"]["mlock-$name_of_board"]; lambda: 'return status_code == 200;'
}); then: # when found, check if machine is allowed, turn on output or blink LED red
- if: - lambda: |-
condition: json::parse_json(id(http_request_data).get_string(), [](JsonObject root) {
lambda: 'return id(may_switch_output);' id(access_allowed) = (root["data"]["mlock-$name_of_board"] == "1");
then: });
- if: - if:
condition: condition:
switch.is_on: mlock_${name_of_board}_switch lambda: 'return id(access_allowed);'
then: then:
- switch.turn_off: mlock_${name_of_board}_switch - script.execute: toggle_switch
- homeassistant.event: - script.execute: cache_token
event: esphome.mlock_locked - script.wait: toggle_switch
data: else:
tag: !lambda return id(my_tag); - repeat:
machine: ${name_of_board} count: 3
else: then:
- switch.turn_on: mlock_${name_of_board}_switch - light.addressable_set: { id: status_led, red: 100%, green: 0%, blue: 0% }
- homeassistant.event: - delay: 0.1s
event: esphome.mlock_unlocked - light.addressable_set: { id: status_led, red: 0%, green: 0%, blue: 0% }
data: - delay: 0.1s
tag: !lambda return id(my_tag); else: # vault returns 404 on missing/unknown Tag so blink LED
machine: ${name_of_board} - repeat:
- text.set: count: 3
id: ${name_of_board}_letzte_entsperrung then:
value: !lambda return id(my_tag); - light.addressable_set: { id: status_led, red: 100%, green: 0%, blue: 0% }
else: - delay: 0.5s
- repeat: - light.addressable_set: { id: status_led, red: 0%, green: 0%, blue: 0% }
count: 3 - delay: 0.5s
then: - if: # return LED to switch state before
- light.addressable_set: { id: status_led, red: 100%, green: 0%, blue: 0% } condition:
- delay: 0.1s switch.is_on: mlock_${name_of_board}_switch
- light.addressable_set: { id: status_led, red: 0%, green: 0%, blue: 0% } then:
- delay: 0.1s - light.addressable_set: { id: status_led, red: 0%, green: 100%, blue: 0% }
else: # vault returns 404 on missing/unknown Tag so blink LED else:
- repeat: - light.addressable_set: { id: status_led, red: 100%, green: 0%, blue: 0% }
count: 3 - id: toggle_switch
then: then:
- light.addressable_set: { id: status_led, red: 100%, green: 0%, blue: 0% } - if:
- delay: 0.5s condition:
- light.addressable_set: { id: status_led, red: 0%, green: 0%, blue: 0% } switch.is_on: mlock_${name_of_board}_switch
- delay: 0.5s then:
- if: # return LED to switch state before - switch.turn_off: mlock_${name_of_board}_switch
condition: - homeassistant.event:
switch.is_on: mlock_${name_of_board}_switch event: esphome.mlock_locked
then: data:
- light.addressable_set: { id: status_led, red: 0%, green: 100%, blue: 0% } tag: !lambda return id(rfid_tag);
else: machine: ${name_of_board}
- light.addressable_set: { id: status_led, red: 100%, green: 0%, blue: 0% } else:
- switch.turn_on: mlock_${name_of_board}_switch
- homeassistant.event:
event: esphome.mlock_unlocked
data:
tag: !lambda return id(rfid_tag);
machine: ${name_of_board}
- text.set:
id: ${name_of_board}_letzte_entsperrung
value: !lambda return id(rfid_tag);
- id: cache_token
then:
- lambda: |-
int rfid_value = decode_token(id(rfid_tag));
int rfid_value_pos = 23;
// search the token in the list to keep the access_cache unique
for (int i = 0; i < 24; i++) {
if (id(access_cache)[i] == rfid_value) {
rfid_value_pos = i;
break;
}
}
// shift the existing entries down
for (int i = rfid_value_pos; i >= 1; i--) {
id(access_cache)[i] = id(access_cache)[i - 1];
}
// write the new token to the start
id(access_cache)[0] = rfid_value;
rc522_spi:
cs_pin: GPIO15
on_tag:
then:
- light.addressable_set: { id: status_led, red: 100%, green: 60%, blue: 0% }
# small delay so the light can update its color
- delay: 15ms
# store the tag id into global variable
- lambda: |-
id(rfid_tag) = x;
- script.execute: check_access
- text.set: - text.set:
id: ${name_of_board}_letzter_token id: ${name_of_board}_letzter_token
value: !lambda return id(my_tag); value: !lambda return id(rfid_tag);
# switch component for the output state # switch component for the output state
switch: switch:
@ -208,6 +272,14 @@ button:
on_press: on_press:
- switch.turn_off: mlock_${name_of_board}_switch - switch.turn_off: mlock_${name_of_board}_switch
- light.addressable_set: { id: status_led, red: 100%, green: 0%, blue: 0% } - light.addressable_set: { id: status_led, red: 100%, green: 0%, blue: 0% }
- platform: template
name: "${name_of_board} Tokencache leeren"
id: ${name_of_board}_btn_tokencache_leeren
on_press:
- lambda: |-
for (int i = 0; i < 24; i++) {
id(access_cache)[i] = 0;
}
light: light:
- platform: neopixelbus - platform: neopixelbus