From 4f60bf416878951149a82b5af4a7189589262922 Mon Sep 17 00:00:00 2001 From: Yorick van Pelt Date: Sun, 24 Sep 2023 22:20:41 +0200 Subject: [PATCH] webhook for amazing marvin status --- .gitignore | 2 +- bin/marvin-sub.sh | 4 + home-manager/waybar.toml | 3 +- nixos/machines/frumar/default.nix | 5 + nixos/modules/marvin-tracker.nix | 55 +++++ nixos/roles/default.nix | 1 + pkgs/default.nix | 3 + pkgs/marvin-tracker/default.nix | 7 + pkgs/marvin-tracker/index.js | 153 ++++++++++++++ pkgs/marvin-tracker/package.json | 14 ++ pkgs/marvin-tracker/yarn.lock | 320 ++++++++++++++++++++++++++++++ 11 files changed, 564 insertions(+), 3 deletions(-) create mode 100755 bin/marvin-sub.sh create mode 100644 nixos/modules/marvin-tracker.nix create mode 100644 pkgs/marvin-tracker/default.nix create mode 100755 pkgs/marvin-tracker/index.js create mode 100644 pkgs/marvin-tracker/package.json create mode 100644 pkgs/marvin-tracker/yarn.lock diff --git a/.gitignore b/.gitignore index 519641d..f32a508 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,4 @@ result /mutt/.mutt/hcache-lock /emacs/emacs.el .direnv - +/pkgs/marvin-tracker/node_modules diff --git a/bin/marvin-sub.sh b/bin/marvin-sub.sh new file mode 100755 index 0000000..d422473 --- /dev/null +++ b/bin/marvin-sub.sh @@ -0,0 +1,4 @@ +#!/bin/sh +set -euo pipefail +export PATH=$HOME/.nix-profile/bin:$PATH +mosquitto_sub -h frumar.home.yori.cc -u iot -P asdf -t "yorick/marvin/tracking" | jq --unbuffered -r 'if .task then if .started then "▶ \(.task.title)" else "⏸ \(.task.title)" end else "" end' diff --git a/home-manager/waybar.toml b/home-manager/waybar.toml index 2baade7..d420820 100644 --- a/home-manager/waybar.toml +++ b/home-manager/waybar.toml @@ -87,5 +87,4 @@ exec = "$HOME/dotfiles/bin/spotify_meta.sh 2> /dev/null" format = "{}" escape = true max-length = 40 -exec = "/home/yorick/tmp/marvin-cli --public tracking --json | /home/yorick/.nix-profile/bin/jq -r .title" -interval = 120 +exec = "$HOME/dotfiles/bin/marvin-sub.sh" diff --git a/nixos/machines/frumar/default.nix b/nixos/machines/frumar/default.nix index a01c558..c4a19b9 100644 --- a/nixos/machines/frumar/default.nix +++ b/nixos/machines/frumar/default.nix @@ -60,6 +60,10 @@ proxyPass = "http://127.0.0.1:7878"; extraConfig = oauth2Block; }; + locations."/marvin-tracker/" = { + proxyPass = "http://[::1]:4001/"; + # handles auth using arg + }; }; virtualHosts."frumar.yori.cc" = { enableACME = lib.mkForce false; @@ -227,4 +231,5 @@ host = "127.0.0.1"; configFile = "${../../../dashy.yaml}"; }; + services.yorick.marvin-tracker.enable = true; } diff --git a/nixos/modules/marvin-tracker.nix b/nixos/modules/marvin-tracker.nix new file mode 100644 index 0000000..ef26c30 --- /dev/null +++ b/nixos/modules/marvin-tracker.nix @@ -0,0 +1,55 @@ +{ config, lib, pkgs, ... }: +let cfg = config.services.yorick.marvin-tracker; in +{ + options.services.yorick.marvin-tracker = with lib; { + enable = mkEnableOption "Marvin Tracker server"; + host = mkOption { + default = "::1"; + type = types.str; + }; + port = mkOption { + default = 4001; + type = types.port; + }; + package = mkOption { + default = pkgs.marvin-tracker; + type = types.package; + }; + mqtt.topic = mkOption { + default = "yorick/marvin/tracking"; + type = types.str; + }; + mqtt.host = mkOption { + default = "localhost"; + type = types.str; + }; + secretFile = mkOption { + type = types.path; + default = "/dev/null"; + }; + api_hash = mkOption { + type = types.str; + default = "z6mzC2TGdVCRuFE+oCrwj1GCHyP6OzYcPKZDiO/yLdqpmChC6S7ijCEUSY5gtqhpXhtYeDRyBjNeVJ/0Se4jQQ=="; + description = "public key for the secret header value"; + }; + }; + config = lib.mkIf cfg.enable { + systemd.services.marvin-tracker = { + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "simple"; + DynamicUser = true; + Restart = "on-failure"; + ExecStart = "${cfg.package}/index.js"; + EnvironmentFile = cfg.secretFile; + }; + environment = { + HOST = cfg.host; + PORT = toString cfg.port; + TOPIC = cfg.mqtt.topic; + API_HASH = cfg.api_hash; + }; + }; + }; +} diff --git a/nixos/roles/default.nix b/nixos/roles/default.nix index 2f56b3b..cbd3f8d 100644 --- a/nixos/roles/default.nix +++ b/nixos/roles/default.nix @@ -10,6 +10,7 @@ in { ../modules/nginx.nix ../modules/lumi-cache.nix ../modules/lumi-vpn.nix + ../modules/marvin-tracker.nix ../modules/muflax-blog.nix ../modules/selfsigned.nix ../services diff --git a/pkgs/default.nix b/pkgs/default.nix index 9e261b0..873a6c9 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -35,6 +35,9 @@ y-deployer = self.callPackage ../deployer/package.nix { inherit (self.nix-npm-buildpackage) buildYarnPackage; }; + marvin-tracker = self.callPackage ./marvin-tracker { + inherit (self.nix-npm-buildpackage) buildYarnPackage; + }; grott = self.callPackage ./grott.nix {}; python3 = super.python3.override { packageOverrides = pyself: pysuper: { diff --git a/pkgs/marvin-tracker/default.nix b/pkgs/marvin-tracker/default.nix new file mode 100644 index 0000000..219d5f3 --- /dev/null +++ b/pkgs/marvin-tracker/default.nix @@ -0,0 +1,7 @@ +{ lib, buildYarnPackage }: +buildYarnPackage { + src = ./.; + postInstall = '' + rm -rf $out/yarn-cache $out/bin/yarn + ''; +} diff --git a/pkgs/marvin-tracker/index.js b/pkgs/marvin-tracker/index.js new file mode 100755 index 0000000..c98d4bc --- /dev/null +++ b/pkgs/marvin-tracker/index.js @@ -0,0 +1,153 @@ +#!/usr/bin/env node +import http from 'node:http'; +import * as mqtt from "mqtt" +import { createHash, timingSafeEqual } from "node:crypto" + +const settings = { + mqtt_host: process.env.MQTT_HOST || "localhost", + mqtt_username: process.env.MQTT_USER || "guest", + mqtt_password: process.env.MQTT_PASSWORD || "guest", + topic: process.env.TOPIC || "yorick/marvin/tracking", + api_hash: process.env.API_HASH || "z6mzC2TGdVCRuFE+oCrwj1GCHyP6OzYcPKZDiO/yLdqpmChC6S7ijCEUSY5gtqhpXhtYeDRyBjNeVJ/0Se4jQQ==", + listen_port: +process.env.PORT || 3000, + listen_host: process.env.HOST || "::", +} + +const client = mqtt.connect(`mqtt://${settings.mqtt_host}`, { + username: settings.mqtt_username, + password: settings.mqtt_password +}); + +let currently_tracking = {} + +client.subscribe(settings.topic) + +client.on("connect", () => { + console.log("mqtt connected") +}) +client.on("message", (topic, message) => { + if (topic == settings.topic) { + try { + currently_tracking = JSON.parse(message) + } catch(e) { + console.warn("unable to parse message", msg) + } + } +}) + +function checkKey(password) { + if (typeof password !== "string") return false + // would be nice if this took salt + const h = createHash("blake2b512") + // salt + h.update("O9yn_qX_jz68H-B6BrkEzRGAWfInzgeOmsCajTJVwcw=") + h.update(password) + // more salt + h.update("LHVV58vOGu7pKSV_Ofmes2joHCal6-F9UuhNLvOK7HM=") + const d = h.digest() + return timingSafeEqual(Buffer.from(settings.api_hash, "base64"), d) +} + +async function waitForJSON(req, max_size) { + return new Promise((resolve, reject) => { + let body = []; + let accumulatedSize = 0; + + req.on('data', (chunk) => { + accumulatedSize += chunk.length; + + if (accumulatedSize > max_size) { + reject({statusCode: 413, message: 'Payload too large'}); + req.connection.destroy(); + } else { + body.push(chunk); + } + }); + + req.on('end', () => { + try { + const parsedBody = JSON.parse(Buffer.concat(body).toString()); + resolve(parsedBody); + } catch (e) { + reject({statusCode: 400, message: 'Bad Request'}); + } + }); + + req.on('error', (err) => { + reject({statusCode: 500, message: 'Internal Server Error'}); + }); + }); +} + +const supported_urls = ["startTracking", "stopTracking", "markDoneTask", "deleteTask", "editTask"] + +async function setTrack(track) { + track.time = Date.now() + currently_tracking = track + await client.publishAsync(settings.topic, JSON.stringify(track), { + retain: true + }) +} + +const endpoints = { + async startTracking(task) { + await setTrack({ task, started: true }) + }, + async stopTracking(task) { + if (task.done) { + await setTrack({}) + } else { + await setTrack({ task, started: false }) + } + }, + async markDoneTask(task) { + if (task._id == currently_tracking.task?._id) + await setTrack({}) + }, + async deleteTask(task) { + if (task._id == currently_tracking.task?._id) + await setTrack({}) + }, + async editTask(task) { + if (task._id == currently_tracking.task?._id) + await setTrack({ task, started: currently_tracking.started }) + } +} + +// todo: check headers +async function handle(req, res) { + console.log(req.method, req.url) + if (endpoints[req.url.slice(1)]) { + res.setHeader('Access-Control-Allow-Origin', '*'); + res.setHeader('Access-Control-Allow-Methods', 'POST'); + res.setHeader('Access-Control-Allow-Headers', 'Content-Type, X-Marv-Key'); + if (req.method == "OPTIONS") {} + else if (req.method == "POST") { + if (!checkKey(req.headers["x-marv-key"])) { + throw { statusCode: 403, message: "auth required" } + } + const body = await waitForJSON(req, 1024 * 512) // 512 kb + await endpoints[req.url.slice(1)](body) + res.end() + } else { + throw { statusCode: 405, message: "Method not supported" } + } + res.end() + } else { + throw { statusCode: 404, message: "Unknown endpoint" } + } +} + +const server = http.createServer(async (req, res) => { + try { + await handle(req, res); + } catch (err) { + console.warn("error in request", err) + res.writeHead(err.statusCode || 500, {'Content-Type': 'text/plain'}).end(err.message || 'Internal Server Error'); + } +}) + + +server.listen(settings.listen_port, settings.listen_host, () => { + console.log(`Server running on http://${settings.listen_host}:${settings.listen_port}/`); +}); diff --git a/pkgs/marvin-tracker/package.json b/pkgs/marvin-tracker/package.json new file mode 100644 index 0000000..20c2443 --- /dev/null +++ b/pkgs/marvin-tracker/package.json @@ -0,0 +1,14 @@ +{ + "name": "marvin-tracker", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "type": "module", + "dependencies": { + "mqtt": "^5.0.5" + }, + "private": true, + "bin": { + "server": "./index.js" + } +} diff --git a/pkgs/marvin-tracker/yarn.lock b/pkgs/marvin-tracker/yarn.lock new file mode 100644 index 0000000..33687d4 --- /dev/null +++ b/pkgs/marvin-tracker/yarn.lock @@ -0,0 +1,320 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@types/node@*": + version "20.6.4" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.6.4.tgz#7882cb8b8adc3106c352dac9c02d4d3ebb95cf3e" + integrity sha512-nU6d9MPY0NBUMiE/nXd2IIoC4OLvsLpwAjheoAeuzgvDZA1Cb10QYg+91AF6zQiKWRN5i1m07x6sMe0niBznoQ== + +"@types/readable-stream@^4.0.1": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@types/readable-stream/-/readable-stream-4.0.2.tgz#5199cfeef35ea16d0e85076b1c6daa15766634c0" + integrity sha512-hhzOsMEISZ+mX1l+01F0duYt9wHEbCGmjARed0PcQoVS5zAdu7u5YbWYuNGhw09M1MgGr3kfsto+ut/MnAdKqA== + dependencies: + "@types/node" "*" + safe-buffer "~5.1.1" + +"@types/ws@^8.5.5": + version "8.5.5" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.5.tgz#af587964aa06682702ee6dcbc7be41a80e4b28eb" + integrity sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg== + dependencies: + "@types/node" "*" + +abort-controller@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== + dependencies: + event-target-shim "^5.0.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +bl@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-5.1.0.tgz#183715f678c7188ecef9fe475d90209400624273" + integrity sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ== + dependencies: + buffer "^6.0.3" + inherits "^2.0.4" + readable-stream "^3.4.0" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +buffer@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + +commist@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/commist/-/commist-3.2.0.tgz#da9c8e5f245ac21510badc4b10c46b5bcc9b56cd" + integrity sha512-4PIMoPniho+LqXmpS5d3NuGYncG6XWlkBSVGiWycL22dd42OYdUGil2CWuzklaJoNxyxUSpO4MKIBU94viWNAw== + +concat-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-2.0.0.tgz#414cf5af790a48c60ab9be4527d56d5e41133cb1" + integrity sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A== + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^3.0.2" + typedarray "^0.0.6" + +debug@^4.1.1, debug@^4.3.1, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +duplexify@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-4.1.2.tgz#18b4f8d28289132fa0b9573c898d9f903f81c7b0" + integrity sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw== + dependencies: + end-of-stream "^1.4.1" + inherits "^2.0.3" + readable-stream "^3.1.1" + stream-shift "^1.0.0" + +end-of-stream@^1.4.1: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +event-target-shim@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + +events@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +glob@^8.0.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" + integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^5.0.1" + once "^1.3.0" + +help-me@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/help-me/-/help-me-4.2.0.tgz#50712bfd799ff1854ae1d312c36eafcea85b0563" + integrity sha512-TAOnTB8Tz5Dw8penUuzHVrKNKlCIbwwbHnXraNJxPwf8LRtE2HlM84RYuezMFcwOJmoYOCWVDyJ8TQGxn9PgxA== + dependencies: + glob "^8.0.0" + readable-stream "^3.6.0" + +ieee754@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.3, inherits@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +js-sdsl@4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.3.0.tgz#aeefe32a451f7af88425b11fdb5f58c90ae1d711" + integrity sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ== + +lru-cache@^7.18.3: + version "7.18.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" + integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== + +minimatch@^5.0.1: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +mqtt-packet@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/mqtt-packet/-/mqtt-packet-8.2.0.tgz#07cfdf72771f2c17c5689183162d1e4ad613438f" + integrity sha512-21Vo7XdRXUw2qhdTfk8GeOl2jtb8Dkwd4dKxn/epvf37mxTxHodvBJoozTPZGVwh57JXlsh2ChsaxMsAfqxp+A== + dependencies: + bl "^5.0.0" + debug "^4.1.1" + process-nextick-args "^2.0.1" + +mqtt@^5.0.5: + version "5.0.5" + resolved "https://registry.yarnpkg.com/mqtt/-/mqtt-5.0.5.tgz#645819f48d6f3dba7962c28c5392e9b696c7081a" + integrity sha512-Ahbzk7nddvYg0aOezbYl/d9o8wcEbZw1NjiH+CmGObxiHsG4HgL7+IaRkph5yxwH679GVMAwtfsyUY2dFBSVSw== + dependencies: + "@types/readable-stream" "^4.0.1" + "@types/ws" "^8.5.5" + commist "^3.2.0" + concat-stream "^2.0.0" + debug "^4.3.4" + duplexify "^4.1.2" + help-me "^4.2.0" + lru-cache "^7.18.3" + minimist "^1.2.8" + mqtt-packet "^8.2.0" + number-allocator "^1.0.14" + readable-stream "^4.4.2" + reinterval "^1.1.0" + rfdc "^1.3.0" + split2 "^4.2.0" + ws "^8.13.0" + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +number-allocator@^1.0.14: + version "1.0.14" + resolved "https://registry.yarnpkg.com/number-allocator/-/number-allocator-1.0.14.tgz#1f2e32855498a7740dcc8c78bed54592d930ee4d" + integrity sha512-OrL44UTVAvkKdOdRQZIJpLkAdjXGTRda052sN4sO77bKEzYYqWKMBjQvrJFzqygI99gL6Z4u2xctPW1tB8ErvA== + dependencies: + debug "^4.3.1" + js-sdsl "4.3.0" + +once@^1.3.0, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +process-nextick-args@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== + +readable-stream@^3.0.2, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readable-stream@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-4.4.2.tgz#e6aced27ad3b9d726d8308515b9a1b98dc1b9d13" + integrity sha512-Lk/fICSyIhodxy1IDK2HazkeGjSmezAWX2egdtJnYhtzKEsBPJowlI6F6LPb5tqIQILrMbx22S5o3GuJavPusA== + dependencies: + abort-controller "^3.0.0" + buffer "^6.0.3" + events "^3.3.0" + process "^0.11.10" + string_decoder "^1.3.0" + +reinterval@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/reinterval/-/reinterval-1.1.0.tgz#3361ecfa3ca6c18283380dd0bb9546f390f5ece7" + integrity sha512-QIRet3SYrGp0HUHO88jVskiG6seqUGC5iAG7AwI/BV4ypGcuqk9Du6YQBUOUqm9c8pw1eyLoIaONifRua1lsEQ== + +rfdc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" + integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== + +safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +split2@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" + integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== + +stream-shift@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" + integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== + +string_decoder@^1.1.1, string_decoder@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== + +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +ws@^8.13.0: + version "8.14.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.14.2.tgz#6c249a806eb2db7a20d26d51e7709eab7b2e6c7f" + integrity sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==