From ce18b83ece710d5717a966a34af4a1b482d06d9d Mon Sep 17 00:00:00 2001 From: neri Date: Sat, 20 Jul 2024 04:25:03 +0200 Subject: [PATCH] mlock: cache valid tokens --- mlock-common.h | 9 ++ mlock-common.yaml | 238 ++++++++++++++++++++++++++++++---------------- 2 files changed, 164 insertions(+), 83 deletions(-) create mode 100644 mlock-common.h diff --git a/mlock-common.h b/mlock-common.h new file mode 100644 index 0000000..b70d5b4 --- /dev/null +++ b/mlock-common.h @@ -0,0 +1,9 @@ +#include +#include + +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(std::stoll(token, nullptr, 16)); +} diff --git a/mlock-common.yaml b/mlock-common.yaml index 67571f4..bb6117a 100644 --- a/mlock-common.yaml +++ b/mlock-common.yaml @@ -13,8 +13,8 @@ substitutions: ###### nothing to change below this line ###### esphome: name: mlock-${name_of_board} - platform: ESP8266 - board: d1_mini + includes: + - mlock-common.h on_boot: - priority: 300 then: @@ -29,6 +29,10 @@ esphome: else: - 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 logger: @@ -67,27 +71,48 @@ http_request: id: http_request_data globals: - - id: my_token + - id: vault_api_token type: std::string restore_value: no - - id: my_tag + - id: rfid_tag type: std::string restore_value: no - - id: may_switch_output - type: int + - id: access_allowed + type: bool 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: - cs_pin: GPIO15 - on_tag: +script: + - id: check_access + 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: - - 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 - http_request.post: url: https://vault.ctdo.de/v1/auth/approle/login @@ -98,79 +123,118 @@ rc522_spi: role_id: $vault_role_id secret_id: $vault_secret_id on_response: - # fetch token from response, store into my_token + # fetch token from response, store into vault_api_token then: - lambda: |- 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 - - http_request.get: - url: !lambda |- - return ((std::string) "https://vault.ctdo.de/v1/maschinenlock/" + id(my_tag)); - verify_ssl: false - headers: - X-Vault-Token: !lambda return id(my_token).c_str(); - on_response: - then: - - if: - condition: - lambda: 'return status_code == 200;' - then: # when found, check if machine is allowed, turn on output or blink LED red - - lambda: |- - json::parse_json(id(http_request_data).get_string(), [](JsonObject root) { - id(may_switch_output) = root["data"]["mlock-$name_of_board"]; - }); - - if: - condition: - lambda: 'return id(may_switch_output);' - then: - - if: - condition: - switch.is_on: mlock_${name_of_board}_switch - then: - - switch.turn_off: mlock_${name_of_board}_switch - - homeassistant.event: - event: esphome.mlock_locked - data: - tag: !lambda return id(my_tag); - machine: ${name_of_board} - else: - - switch.turn_on: mlock_${name_of_board}_switch - - homeassistant.event: - event: esphome.mlock_unlocked - data: - tag: !lambda return id(my_tag); - machine: ${name_of_board} - - text.set: - id: ${name_of_board}_letzte_entsperrung - value: !lambda return id(my_tag); - else: - - repeat: - count: 3 - then: - - light.addressable_set: { id: status_led, red: 100%, green: 0%, blue: 0% } - - delay: 0.1s - - light.addressable_set: { id: status_led, red: 0%, green: 0%, blue: 0% } - - delay: 0.1s - else: # vault returns 404 on missing/unknown Tag so blink LED - - repeat: - count: 3 - then: - - light.addressable_set: { id: status_led, red: 100%, green: 0%, blue: 0% } - - delay: 0.5s - - light.addressable_set: { id: status_led, red: 0%, green: 0%, blue: 0% } - - delay: 0.5s - - 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% } + - script.execute: check_access_vault + - id: check_access_vault + then: + - lambda: |- + id(access_allowed) = false; + - http_request.get: + url: !lambda |- + return ((std::string) "https://vault.ctdo.de/v1/maschinenlock/" + id(rfid_tag)); + verify_ssl: false + headers: + X-Vault-Token: !lambda return id(vault_api_token).c_str(); + on_response: + then: + - if: + condition: + lambda: 'return status_code == 200;' + then: # when found, check if machine is allowed, turn on output or blink LED red + - lambda: |- + json::parse_json(id(http_request_data).get_string(), [](JsonObject root) { + id(access_allowed) = (root["data"]["mlock-$name_of_board"] == "1"); + }); + - if: + condition: + lambda: 'return id(access_allowed);' + then: + - script.execute: toggle_switch + - script.execute: cache_token + - script.wait: toggle_switch + else: + - repeat: + count: 3 + then: + - light.addressable_set: { id: status_led, red: 100%, green: 0%, blue: 0% } + - delay: 0.1s + - light.addressable_set: { id: status_led, red: 0%, green: 0%, blue: 0% } + - delay: 0.1s + else: # vault returns 404 on missing/unknown Tag so blink LED + - repeat: + count: 3 + then: + - light.addressable_set: { id: status_led, red: 100%, green: 0%, blue: 0% } + - delay: 0.5s + - light.addressable_set: { id: status_led, red: 0%, green: 0%, blue: 0% } + - delay: 0.5s + - 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% } + - id: toggle_switch + then: + - if: + condition: + switch.is_on: mlock_${name_of_board}_switch + then: + - switch.turn_off: mlock_${name_of_board}_switch + - homeassistant.event: + event: esphome.mlock_locked + data: + tag: !lambda return id(rfid_tag); + machine: ${name_of_board} + 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: 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: @@ -208,6 +272,14 @@ button: on_press: - switch.turn_off: mlock_${name_of_board}_switch - 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: - platform: neopixelbus