diff --git a/packages/parental_controls.yaml b/packages/parental_controls.yaml index f4f1985..1a1a01e 100644 --- a/packages/parental_controls.yaml +++ b/packages/parental_controls.yaml @@ -1 +1,161 @@ -IyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgUGFyZW50YWwgQ29udHJvbHMgUGFja2FnZQojIFJlcXVpcmVzIE9QTnNlbnNlIGZpcmV3YWxsIGFsaWFzICJwYXJlbnRhbF9ibG9ja2VkIiArIHJ1bGUKIyBTZWUgUkVBRE1FLm1kIGZvciBmdWxsIHNldHVwIGluc3RydWN0aW9ucwojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KCmlucHV0X3RleHQ6CiAgcGFyZW50YWxfY29udHJvbF9jb25maWc6CiAgICBuYW1lOiBQYXJlbnRhbCBDb250cm9scyBDb25maWd1cmF0aW9uCiAgICBtYXg6IDEwMDAwCiAgICBpbml0aWFsOiAneyJ1c2VycyI6W119JwogICAgaWNvbjogbWRpOnNoaWVsZC1hY2NvdW50CgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIE9QTnNlbnNlIEFQSSBjYWxscwojIFNlY3JldHMgcmVxdWlyZWQgaW4gc2VjcmV0cy55YW1sIOKAlCBzZWUgc2VjcmV0c19leGFtcGxlLnlhbWwKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KcmVzdF9jb21tYW5kOgoKICBwYXJlbnRhbF9ibG9ja19pcDoKICAgIHVybDogIXNlY3JldCBvcG5zZW5zZV9hbGlhc19hZGRfdXJsCiAgICBtZXRob2Q6IHBvc3QKICAgIGhlYWRlcnM6CiAgICAgIEF1dGhvcml6YXRpb246ICFzZWNyZXQgb3Buc2Vuc2VfYmFzaWNfYXV0aAogICAgcGF5bG9hZDogImFkZHJlc3M9e3sgYWRkcmVzcyB9fSIKICAgIGNvbnRlbnRfdHlwZTogImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCIKICAgIHZlcmlmeV9zc2w6IGZhbHNlCgogIHBhcmVudGFsX3VuYmxvY2tfaXA6CiAgICB1cmw6ICFzZWNyZXQgb3Buc2Vuc2VfYWxpYXNfZGVsX3VybAogICAgbWV0aG9kOiBwb3N0CiAgICBoZWFkZXJzOgogICAgICBBdXRob3JpemF0aW9uOiAhc2VjcmV0IG9wbnNlbnNlX2Jhc2ljX2F1dGgKICAgIHBheWxvYWQ6ICJhZGRyZXNzPXt7IGFkZHJlc3MgfX0iCiAgICBjb250ZW50X3R5cGU6ICJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQiCiAgICB2ZXJpZnlfc3NsOiBmYWxzZQoKICBwYXJlbnRhbF9hcHBseV9maXJld2FsbDoKICAgIHVybDogIXNlY3JldCBvcG5zZW5zZV9hcHBseV91cmwKICAgIG1ldGhvZDogcG9zdAogICAgaGVhZGVyczoKICAgICAgQXV0aG9yaXphdGlvbjogIXNlY3JldCBvcG5zZW5zZV9iYXNpY19hdXRoCiAgICBwYXlsb2FkOiAie30iCiAgICBjb250ZW50X3R5cGU6ICJhcHBsaWNhdGlvbi9qc29uIgogICAgdmVyaWZ5X3NzbDogZmFsc2UKCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiMgU2NyaXB0cyDigJQgY2FsbGVkIGZyb20gdGhlIGRhc2hib2FyZCB2aWEgSEEgV2ViU29ja2V0CiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCnNjcmlwdDoKCiAgcGFyZW50YWxfYmxvY2tfaXA6CiAgICBhbGlhczogIlBhcmVudGFsIENvbnRyb2xzIOKAlCBCbG9jayBJUCIKICAgIGRlc2NyaXB0aW9uOiAiQWRkcyBhbiBJUCB0byB0aGUgT1BOc2Vuc2UgcGFyZW50YWxfYmxvY2tlZCBhbGlhcyIKICAgIGljb246IG1kaTpibG9jay1oZWxwZXIKICAgIGZpZWxkczoKICAgICAgaXA6CiAgICAgICAgZGVzY3JpcHRpb246ICJJUCBhZGRyZXNzIHRvIGJsb2NrIgogICAgICAgIHJlcXVpcmVkOiB0cnVlCiAgICAgICAgc2VsZWN0b3I6CiAgICAgICAgICB0ZXh0OgogICAgc2VxdWVuY2U6CiAgICAgIC0gc2VydmljZTogcmVzdF9jb21tYW5kLnBhcmVudGFsX2Jsb2NrX2lwCiAgICAgICAgZGF0YToKICAgICAgICAgIGFkZHJlc3M6ICJ7eyBpcCB9fSIKCiAgcGFyZW50YWxfdW5ibG9ja19pcDoKICAgIGFsaWFzOiAiUGFyZW50YWwgQ29udHJvbHMg4oCUIFVuYmxvY2sgSVAiCiAgICBkZXNjcmlwdGlvbjogIlJlbW92ZXMgYW4gSVAgZnJvbSB0aGUgT1BOc2Vuc2UgcGFyZW50YWxfYmxvY2tlZCBhbGlhcyIKICAgIGljb246IG1kaTpjaGVjay1jaXJjbGUtb3V0bGluZQogICAgZmllbGRzOgogICAgICBpcDoKICAgICAgICBkZXNjcmlwdGlvbjogIklQIGFkZHJlc3MgdG8gdW5ibG9jayIKICAgICAgICByZXF1aXJlZDogdHJ1ZQogICAgICAgIHNlbGVjdG9yOgogICAgICAgICAgdGV4dDoKICAgIHNlcXVlbmNlOgogICAgICAtIHNlcnZpY2U6IHJlc3RfY29tbWFuZC5wYXJlbnRhbF91bmJsb2NrX2lwCiAgICAgICAgZGF0YToKICAgICAgICAgIGFkZHJlc3M6ICJ7eyBpcCB9fSIKCiAgcGFyZW50YWxfYXBwbHlfZmlyZXdhbGw6CiAgICBhbGlhczogIlBhcmVudGFsIENvbnRyb2xzIOKAlCBBcHBseSBGaXJld2FsbCIKICAgIGRlc2NyaXB0aW9uOiAiVGVsbHMgT1BOc2Vuc2UgdG8gY29tbWl0IGFsaWFzIGNoYW5nZXMgdG8gdGhlIGxpdmUgZmlyZXdhbGwiCiAgICBpY29uOiBtZGk6c2hpZWxkLXJlZnJlc2gKICAgIHNlcXVlbmNlOgogICAgICAtIHNlcnZpY2U6IHJlc3RfY29tbWFuZC5wYXJlbnRhbF9hcHBseV9maXJld2FsbAoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyBPcHRpb25hbDogc2NoZWR1bGUgZW5mb3JjZXIgYXV0b21hdGlvbgojIFRoaXMgcnVucyBldmVyeSA1IG1pbnV0ZXMgYW5kIGVuZm9yY2VzIGJsb2NrIHNjaGVkdWxlcyBldmVuIHdoZW4KIyB0aGUgZGFzaGJvYXJkIHBhZ2UgaXNuJ3Qgb3Blbi4gRW5hYmxlIGJ5IHVuY29tbWVudGluZyBiZWxvdy4KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMgYXV0b21hdGlvbjoKIyAgIC0gaWQ6IHBhcmVudGFsX2NvbnRyb2xzX3NjaGVkdWxlX2VuZm9yY2VyCiMgICAgIGFsaWFzOiAiUGFyZW50YWwgQ29udHJvbHMg4oCUIFNjaGVkdWxlIEVuZm9yY2VyIgojICAgICBkZXNjcmlwdGlvbjogIkVuZm9yY2VzIHNjaGVkdWxlZCBibG9ja3MgZnJvbSB0aGUgcGFyZW50YWwgY29udHJvbHMgY29uZmlnIgojICAgICB0cmlnZ2VyOgojICAgICAgIC0gcGxhdGZvcm06IHRpbWVfcGF0dGVybgojICAgICAgICAgbWludXRlczogIi81IgojICAgICBjb25kaXRpb246CiMgICAgICAgLSBjb25kaXRpb246IHRlbXBsYXRlCiMgICAgICAgICB2YWx1ZV90ZW1wbGF0ZTogPgojICAgICAgICAgICB7eyBzdGF0ZXMoJ2lucHV0X3RleHQucGFyZW50YWxfY29udHJvbF9jb25maWcnKSBub3QgaW4gWyd1bmtub3duJywgJ3VuYXZhaWxhYmxlJywgJyddIH19CiMgICAgIGFjdGlvbjoKIyAgICAgICAtIHZhcmlhYmxlczoKIyAgICAgICAgICAgY29uZmlnOiAie3sgc3RhdGVzKCdpbnB1dF90ZXh0LnBhcmVudGFsX2NvbnRyb2xfY29uZmlnJykgfCBmcm9tX2pzb24gfX0iCiMgICAgICAgICAgIGlzX3dlZWtlbmQ6ICJ7eyBub3coKS53ZWVrZGF5KCkgPj0gNSB9fSIKIyAgICAgICAgICAgY3VycmVudF90aW1lOiAie3sgbm93KCkuc3RyZnRpbWUoJyVIOiVNJykgfX0iCiMgICAgICAgLSByZXBlYXQ6CiMgICAgICAgICAgIGZvcl9lYWNoOiAie3sgY29uZmlnLnVzZXJzIH19IgojICAgICAgICAgICBzZXF1ZW5jZToKIyAgICAgICAgICAgICAtIHZhcmlhYmxlczoKIyAgICAgICAgICAgICAgICAgdXNlcjogInt7IHJlcGVhdC5pdGVtIH19IgojICAgICAgICAgICAgICAgICBzY2hlZDogInt7IHJlcGVhdC5pdGVtLnNjaGVkdWxlIH19IgojICAgICAgICAgICAgIC0gY29uZGl0aW9uOiB0ZW1wbGF0ZQojICAgICAgICAgICAgICAgdmFsdWVfdGVtcGxhdGU6ICJ7eyBzY2hlZC5lbmFibGVkIHwgZGVmYXVsdChmYWxzZSkgfX0iCiMgICAgICAgICAgICAgLSB2YXJpYWJsZXM6CiMgICAgICAgICAgICAgICAgIHNsb3Q6ICJ7eyBzY2hlZC53ZWVrZW5kIGlmIGlzX3dlZWtlbmQgZWxzZSBzY2hlZC53ZWVrZGF5IH19IgojICAgICAgICAgICAgICAgICBidDogInt7IHNsb3QuYmxvY2tfdGltZSB9fSIKIyAgICAgICAgICAgICAgICAgdXQ6ICJ7eyBzbG90LnVuYmxvY2tfdGltZSB9fSIKIyAgICAgICAgICAgICAgICAgc2hvdWxkX2Jsb2NrOiA+CiMgICAgICAgICAgICAgICAgICAgeyUgaWYgYnQgPT0gdXQgJX0KIyAgICAgICAgICAgICAgICAgICAgIGZhbHNlCiMgICAgICAgICAgICAgICAgICAgeyUgZWxpZiBidCA8IHV0ICV9CiMgICAgICAgICAgICAgICAgICAgICB7eyBjdXJyZW50X3RpbWUgPj0gYnQgYW5kIGN1cnJlbnRfdGltZSA8IHV0IH19CiMgICAgICAgICAgICAgICAgICAgeyUgZWxzZSAlfQojICAgICAgICAgICAgICAgICAgICAge3sgY3VycmVudF90aW1lID49IGJ0IG9yIGN1cnJlbnRfdGltZSA8IHV0IH19CiMgICAgICAgICAgICAgICAgICAgeyUgZW5kaWYgJX0KIyAgICAgICAgICAgICAtIHJlcGVhdDoKIyAgICAgICAgICAgICAgICAgZm9yX2VhY2g6ICJ7eyB1c2VyLmRldmljZXMgfX0iCiMgICAgICAgICAgICAgICAgIHNlcXVlbmNlOgojICAgICAgICAgICAgICAgICAgIC0gdmFyaWFibGVzOgojICAgICAgICAgICAgICAgICAgICAgICBkZXZpY2U6ICJ7eyByZXBlYXQuaXRlbSB9fSIKIyAgICAgICAgICAgICAgICAgICAgICAgZGV2X21hYzogInt7IGRldmljZS5tYWMgfCBsb3dlciB9fSIKIyAgICAgICAgICAgICAgICAgICAgICAgZGV2X2lwOiA+CiMgICAgICAgICAgICAgICAgICAgICAgICAgeyUgc2V0IHRyYWNrZXJzID0gc3RhdGVzLmRldmljZV90cmFja2VyCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBzZWxlY3RhdHRyKCdhdHRyaWJ1dGVzLm1hYycsICdkZWZpbmVkJykgfCBsaXN0ICV9CiMgICAgICAgICAgICAgICAgICAgICAgICAgeyUgZm9yIHQgaW4gdHJhY2tlcnMgJX0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgIHslIHNldCB0X21hYyA9ICh0LmF0dHJpYnV0ZXMubWFjIHwgZGVmYXVsdCgnJykpIHwgbG93ZXIgJX0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgIHslIGlmIHRfbWFjID09IGRldl9tYWMgYW5kIHQuYXR0cmlidXRlcy5pcCBpcyBkZWZpbmVkICV9CiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHt7IHQuYXR0cmlidXRlcy5pcCB9fXslIGJyZWFrICV9CiMgICAgICAgICAgICAgICAgICAgICAgICAgICB7JSBlbmRpZiAlfQojICAgICAgICAgICAgICAgICAgICAgICAgIHslIGVuZGZvciAlfQojICAgICAgICAgICAgICAgICAgIC0gY2hvb3NlOgojICAgICAgICAgICAgICAgICAgICAgICAtIGNvbmRpdGlvbnM6CiMgICAgICAgICAgICAgICAgICAgICAgICAgICAtIGNvbmRpdGlvbjogdGVtcGxhdGUKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVfdGVtcGxhdGU6ICJ7eyBzaG91bGRfYmxvY2sgYW5kIGRldl9pcCB8IGxlbmd0aCA+IDAgfX0iCiMgICAgICAgICAgICAgICAgICAgICAgICAgc2VxdWVuY2U6CiMgICAgICAgICAgICAgICAgICAgICAgICAgICAtIHNlcnZpY2U6IHNjcmlwdC5wYXJlbnRhbF9ibG9ja19pcAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhOgojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlwOiAie3sgZGV2X2lwIH19IgojICAgICAgICAgICAgICAgICAgICAgICAtIGNvbmRpdGlvbnM6CiMgICAgICAgICAgICAgICAgICAgICAgICAgICAtIGNvbmRpdGlvbjogdGVtcGxhdGUKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVfdGVtcGxhdGU6ICJ7eyBub3Qgc2hvdWxkX2Jsb2NrIGFuZCBkZXZfaXAgfCBsZW5ndGggPiAwIH19IgojICAgICAgICAgICAgICAgICAgICAgICAgIHNlcXVlbmNlOgojICAgICAgICAgICAgICAgICAgICAgICAgICAgLSBzZXJ2aWNlOiBzY3JpcHQucGFyZW50YWxfdW5ibG9ja19pcAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhOgojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlwOiAie3sgZGV2X2lwIH19IgojICAgICAgIC0gc2VydmljZTogc2NyaXB0LnBhcmVudGFsX2FwcGx5X2ZpcmV3YWxsCg== \ No newline at end of file +# ============================================================= +# Parental Controls Package +# Requires OPNsense firewall alias "parental_blocked" + rule +# See README.md for full setup instructions +# ============================================================= + +input_text: + parental_control_config: + name: Parental Controls Configuration + max: 10000 + initial: '{"users":[]}' + icon: mdi:shield-account + +# ------------------------------------------------------------------ +# OPNsense API calls +# Secrets required in secrets.yaml — see secrets_example.yaml +# ------------------------------------------------------------------ +rest_command: + + parental_block_ip: + url: !secret opnsense_alias_add_url + method: post + headers: + Authorization: !secret opnsense_basic_auth + payload: "address={{ address }}" + content_type: "application/x-www-form-urlencoded" + verify_ssl: false + + parental_unblock_ip: + url: !secret opnsense_alias_del_url + method: post + headers: + Authorization: !secret opnsense_basic_auth + payload: "address={{ address }}" + content_type: "application/x-www-form-urlencoded" + verify_ssl: false + + parental_apply_firewall: + url: !secret opnsense_apply_url + method: post + headers: + Authorization: !secret opnsense_basic_auth + payload: "{}" + content_type: "application/json" + verify_ssl: false + +# ------------------------------------------------------------------ +# Scripts — called from the dashboard via HA WebSocket +# ------------------------------------------------------------------ +script: + + parental_block_ip: + alias: "Parental Controls — Block IP" + description: "Adds an IP to the OPNsense parental_blocked alias" + icon: mdi:block-helper + fields: + ip: + description: "IP address to block" + required: true + selector: + text: + sequence: + - service: rest_command.parental_block_ip + data: + address: "{{ ip }}" + + parental_unblock_ip: + alias: "Parental Controls — Unblock IP" + description: "Removes an IP from the OPNsense parental_blocked alias" + icon: mdi:check-circle-outline + fields: + ip: + description: "IP address to unblock" + required: true + selector: + text: + sequence: + - service: rest_command.parental_unblock_ip + data: + address: "{{ ip }}" + + parental_apply_firewall: + alias: "Parental Controls — Apply Firewall" + description: "Tells OPNsense to commit alias changes to the live firewall" + icon: mdi:shield-refresh + sequence: + - service: rest_command.parental_apply_firewall + +# ------------------------------------------------------------------ +# Optional: schedule enforcer automation +# This runs every 5 minutes and enforces block schedules even when +# the dashboard page isn't open. Enable by uncommenting below. +# ------------------------------------------------------------------ + +# automation: +# - id: parental_controls_schedule_enforcer +# alias: "Parental Controls — Schedule Enforcer" +# description: "Enforces scheduled blocks from the parental controls config" +# trigger: +# - platform: time_pattern +# minutes: "/5" +# condition: +# - condition: template +# value_template: > +# {{ states('input_text.parental_control_config') not in ['unknown', 'unavailable', ''] }} +# action: +# - variables: +# config: "{{ states('input_text.parental_control_config') | from_json }}" +# is_weekend: "{{ now().weekday() >= 5 }}" +# current_time: "{{ now().strftime('%H:%M') }}" +# - repeat: +# for_each: "{{ config.users }}" +# sequence: +# - variables: +# user: "{{ repeat.item }}" +# sched: "{{ repeat.item.schedule }}" +# - condition: template +# value_template: "{{ sched.enabled | default(false) }}" +# - variables: +# slot: "{{ sched.weekend if is_weekend else sched.weekday }}" +# bt: "{{ slot.block_time }}" +# ut: "{{ slot.unblock_time }}" +# should_block: > +# {% if bt == ut %} +# false +# {% elif bt < ut %} +# {{ current_time >= bt and current_time < ut }} +# {% else %} +# {{ current_time >= bt or current_time < ut }} +# {% endif %} +# - repeat: +# for_each: "{{ user.devices }}" +# sequence: +# - variables: +# device: "{{ repeat.item }}" +# dev_mac: "{{ device.mac | lower }}" +# dev_ip: > +# {% set trackers = states.device_tracker +# | selectattr('attributes.mac', 'defined') | list %} +# {% for t in trackers %} +# {% set t_mac = (t.attributes.mac | default('')) | lower %} +# {% if t_mac == dev_mac and t.attributes.ip is defined %} +# {{ t.attributes.ip }}{% break %} +# {% endif %} +# {% endfor %} +# - choose: +# - conditions: +# - condition: template +# value_template: "{{ should_block and dev_ip | length > 0 }}" +# sequence: +# - service: script.parental_block_ip +# data: +# ip: "{{ dev_ip }}" +# - conditions: +# - condition: template +# value_template: "{{ not should_block and dev_ip | length > 0 }}" +# sequence: +# - service: script.parental_unblock_ip +# data: +# ip: "{{ dev_ip }}" +# - service: script.parental_apply_firewall