From 2aacdf31854547c7623e499117b3871aa310be7e Mon Sep 17 00:00:00 2001 From: Donavan Becker Date: Mon, 24 Jun 2024 20:52:08 -0500 Subject: [PATCH] prepare for v1.0.0 ipv4-mapped ipv6 address change Co-Authored-By: Supereg --- CHANGELOG.md | 7 ++++++- package-lock.json | 16 ++++++++-------- package.json | 4 ++-- src/lib/Characteristic.ts | 6 +++--- src/lib/util/checkName.ts | 5 +++-- src/lib/util/eventedhttp.ts | 29 +++++++++++++++++++++++++---- 6 files changed, 47 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b01711fcc..11fe71c1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,12 @@ All notable changes to `hap-nodejs` will be documented in this file. This project tries to adhere to [Semantic Versioning](http://semver.org/). -## v0.12.3 (2024-06-24) +## ALPHA + +### Breaking Changes + +* **The minimum Node.js version required is now `v18`.** +* **Important notice:** This update bring true semver support. ### Other Changes diff --git a/package-lock.json b/package-lock.json index 4225012b8..d4ef98d8b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "hap-nodejs", - "version": "0.12.3", + "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "hap-nodejs", - "version": "0.12.3", + "version": "1.0.0", "license": "Apache-2.0", "dependencies": { - "@homebridge/ciao": "^1.2.0", + "@homebridge/ciao": "^2.0.0-alpha.4", "@homebridge/dbus-native": "^0.6.0", "bonjour-hap": "^3.7.3", "debug": "^4.3.5", @@ -799,15 +799,15 @@ } }, "node_modules/@homebridge/ciao": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@homebridge/ciao/-/ciao-1.2.0.tgz", - "integrity": "sha512-2Qa8MVC7Q5DKH6iXh6cRvqz9VJYVpVZ+whHKrnr8YdPkXxc67kiQ9IOxMb0ydokDTETBVyXgr1m+HrheBtqDoQ==", + "version": "2.0.0-alpha.4", + "resolved": "https://registry.npmjs.org/@homebridge/ciao/-/ciao-2.0.0-alpha.4.tgz", + "integrity": "sha512-Sog/VEDYM9cgmhURnjeF3zks+6SgZvB2muILdSdGFAlcCCngJXlAQIS4SnUsGjQ1ZKV7q/2ctWMu83QwMKSZpQ==", "license": "MIT", "dependencies": { - "debug": "^4.3.4", + "debug": "^4.3.5", "fast-deep-equal": "^3.1.3", "source-map-support": "^0.5.21", - "tslib": "^2.6.2" + "tslib": "^2.6.3" }, "bin": { "ciao-bcs": "lib/bonjour-conformance-testing.js" diff --git a/package.json b/package.json index d23132c95..64e452150 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hap-nodejs", - "version": "0.12.3", + "version": "1.0.0", "description": "HAP-NodeJS is a Node.js implementation of HomeKit Accessory Server.", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -52,7 +52,7 @@ "@types" ], "dependencies": { - "@homebridge/ciao": "^1.2.0", + "@homebridge/ciao": "^2.0.0-alpha.4", "@homebridge/dbus-native": "^0.6.0", "bonjour-hap": "^3.7.3", "debug": "^4.3.5", diff --git a/src/lib/Characteristic.ts b/src/lib/Characteristic.ts index 221ae125f..14ff76302 100644 --- a/src/lib/Characteristic.ts +++ b/src/lib/Characteristic.ts @@ -2881,8 +2881,8 @@ export class Characteristic extends EventEmitter { // mirrors the case value = null at the beginning if (value.length <= 1 && (this.UUID === Characteristic.Model.UUID || this.UUID === Characteristic.SerialNumber.UUID)) { - this.characteristicWarning(`[${this.displayName}] characteristic must have a length of more than 1 character otherwise \ - HomeKit will reject this accessory, ignoring new value`, warningType); + this.characteristicWarning(`[${this.displayName}] characteristic must have a length of more than 1 character otherwise` + + ` HomeKit will reject this accessory, ignoring new value ${warningType}`); return this.value; // just return the current value } @@ -2893,7 +2893,7 @@ export class Characteristic extends EventEmitter { } if (this.UUID === "000000E3-0000-1000-8000-0026BB765291") { - checkName("unknown", this.displayName, value); + checkName(this.displayName, "ConfiguredName", value); } return value; diff --git a/src/lib/util/checkName.ts b/src/lib/util/checkName.ts index 78a6f75ae..042670e2d 100644 --- a/src/lib/util/checkName.ts +++ b/src/lib/util/checkName.ts @@ -6,11 +6,12 @@ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types export function checkName(displayName: string, name: string, value: any): void { - const validHK = /^[a-zA-Z0-9\s'-.]+$/; // Ensure only letter, numbers, apostrophe, or dash + const empty = !value ? true : false; // Check if value is empty + const validHK = /^[a-zA-Z0-9\s'-.]+$/; // Ensure only letter, numbers, apostrophe, or dash const startWith = /^[a-zA-Z0-9]/; // Ensure only letters or numbers are at the beginning of string const endWith = /[a-zA-Z0-9]$/; // Ensure only letters or numbers are at the end of string - if (!validHK.test(value) || !startWith.test(value) || !endWith.test(value)) { + if (empty || !validHK.test(value) || !startWith.test(value) || !endWith.test(value)) { console.warn("HAP-NodeJS WARNING: The accessory '" + displayName + "' is getting published with the characteristic '" + name + "'" + " not following HomeKit naming rules ('" + value + "'). " + "Use only alphanumeric, space, and apostrophe characters, start and end with an alphabetic or numeric character, and don't include emojis. " + diff --git a/src/lib/util/eventedhttp.ts b/src/lib/util/eventedhttp.ts index 54fb9c1a9..f410d6abe 100644 --- a/src/lib/util/eventedhttp.ts +++ b/src/lib/util/eventedhttp.ts @@ -844,21 +844,42 @@ export class HAPConnection extends EventEmitter { } private static getLocalNetworkInterface(socket: Socket): string { + function formatIPv4MappedIPv6Address(address: string): string { + // Check if the address is an IPv4-mapped IPv6 address without the 'ffff:' part + if (address.startsWith("::") && !address.startsWith("::ffff:")) { + // Attempt to correct the format by adding 'ffff:' after '::' + return address.replace("::", "::ffff:"); + } + return address; + } + let localAddress = socket.localAddress as string; - if (localAddress.startsWith("::ffff:")) { // IPv4-Mapped IPv6 Address https://tools.ietf.org/html/rfc4291#section-2.5.5.2 + localAddress = formatIPv4MappedIPv6Address(localAddress); + + // Check if the address is an IPv4-Mapped IPv6 Address (e.g., ::ffff:192.0.2.128) + // These addresses are IPv6 addresses that represent an IPv4 address + // See: https://tools.ietf.org/html/rfc4291#section-2.5.5.2 for more details + if (localAddress.startsWith("::ffff:")) { + // Extract the IPv4 part from the IPv4-Mapped IPv6 address + // This converts the address from ::ffff:192.0.2.128 to 192.0.2.128 localAddress = localAddress.substring(7); } else { + // For other types of addresses, such as link-local IPv6 addresses, + // remove the interface part (if present) to get the pure address const index = localAddress.indexOf("%"); - if (index !== -1) { // link-local ipv6 + if (index !== -1) { // If it's a link-local ipv6 address localAddress = localAddress.substring(0, index); } } + // Retrieve the network interfaces available on this system const interfaces = os.networkInterfaces(); + // Iterate over each interface to find a match with the localAddress for (const [name, infos] of Object.entries(interfaces)) { if (infos) { for (const info of infos) { + // If the address matches, return the name of the network interface if (info.address === localAddress) { return name; } @@ -883,8 +904,8 @@ export class HAPConnection extends EventEmitter { } } - console.log(`WARNING couldn't map socket coming from remote address ${socket.remoteAddress}:${socket.remotePort} \ - at local address ${socket.localAddress} to a interface!`); + console.log(`WARNING couldn't map socket coming from remote address ${socket.remoteAddress}:${socket.remotePort} ` + + `at local address ${socket.localAddress} to a interface!`); return Object.keys(interfaces)[1]; // just use the first interface after the loopback interface as fallback }