Skip to content

Commit

Permalink
prepare for v1.0.0
Browse files Browse the repository at this point in the history
ipv4-mapped ipv6 address change

added the pattern that is failing

Co-Authored-By: Supereg <[email protected]>
  • Loading branch information
donavanbecker and Supereg committed Jun 28, 2024
1 parent ae9981c commit a12fb8d
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 26 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

<a href="https://www.npmjs.com/package/hap-nodejs"><img title="npm version" src="https://badgen.net/npm/v/hap-nodejs" ></a>
<a href="https://www.npmjs.com/package/hap-nodejs/v/beta"><img title="npm version beta" src="https://badgen.net/npm/v/hap-nodejs/beta" ></a>
<a href="https://www.npmjs.com/package/hap-nodejs/v/alpha"><img title="npm version apha" src="https://badgen.net/npm/v/hap-nodejs/alpha" ></a><br>
<a href="https://www.npmjs.com/package/hap-nodejs"><img title="npm downloads" src="https://badgen.net/npm/dt/hap-nodejs" ></a>
<a href="https://github.com/homebridge/HAP-NodeJS/actions/workflows/build.yml"><img title="Node Build" src="https://github.com/homebridge/HAP-NodeJS/actions/workflows/build.yml/badge.svg" ></a>
<a href='https://coveralls.io/github/homebridge/HAP-NodeJS'><img src='https://coveralls.io/repos/github/homebridge/HAP-NodeJS/badge.svg' alt='Coverage Status' /></a>
Expand Down
16 changes: 8 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down Expand Up @@ -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",
Expand Down
8 changes: 4 additions & 4 deletions src/lib/Characteristic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand All @@ -2892,8 +2892,8 @@ export class Characteristic extends EventEmitter {
value = value.substring(0, maxLength);
}

if (this.UUID === "000000E3-0000-1000-8000-0026BB765291") {
checkName("unknown", this.displayName, value);
if ((value !== null || value !== "") && this.UUID === Characteristic.ConfiguredName.UUID) {
checkName(this.displayName, "ConfiguredName", value);
}

return value;
Expand Down
10 changes: 5 additions & 5 deletions src/lib/util/checkName.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,39 +14,39 @@ describe("#checkName()", () => {
test("Accessory Name ending with !", async () => {
checkName("displayName", "name", "bad name!");

expect(consoleLogSpy).toBeCalledTimes(1);
expect(consoleLogSpy).toHaveBeenCalledTimes(1);
// eslint-disable-next-line max-len
expect(consoleLogSpy).toHaveBeenCalledWith("HAP-NodeJS WARNING: The accessory 'displayName' is getting published with the characteristic 'name' not following HomeKit naming rules ('bad name!'). Use only alphanumeric, space, and apostrophe characters, start and end with an alphabetic or numeric character, and don't include emojis. This might prevent the accessory from being added to the Home App or leading to the accessory being unresponsive!");
});

test("Accessory Name begining with !", async () => {
checkName("displayName", "name", "!bad name");

expect(consoleLogSpy).toBeCalledTimes(1);
expect(consoleLogSpy).toHaveBeenCalledTimes(1);
// eslint-disable-next-line max-len
expect(consoleLogSpy).toHaveBeenCalledWith("HAP-NodeJS WARNING: The accessory 'displayName' is getting published with the characteristic 'name' not following HomeKit naming rules ('!bad name'). Use only alphanumeric, space, and apostrophe characters, start and end with an alphabetic or numeric character, and don't include emojis. This might prevent the accessory from being added to the Home App or leading to the accessory being unresponsive!");
});

test("Accessory Name containing !", async () => {
checkName("displayName", "name", "bad ! name");

expect(consoleLogSpy).toBeCalledTimes(1);
expect(consoleLogSpy).toHaveBeenCalledTimes(1);
// eslint-disable-next-line max-len
expect(consoleLogSpy).toHaveBeenCalledWith("HAP-NodeJS WARNING: The accessory 'displayName' is getting published with the characteristic 'name' not following HomeKit naming rules ('bad ! name'). Use only alphanumeric, space, and apostrophe characters, start and end with an alphabetic or numeric character, and don't include emojis. This might prevent the accessory from being added to the Home App or leading to the accessory being unresponsive!");
});

test("Accessory Name begining with '", async () => {
checkName("displayName", "name", "'bad name");

expect(consoleLogSpy).toBeCalledTimes(1);
expect(consoleLogSpy).toHaveBeenCalledTimes(1);
// eslint-disable-next-line max-len
expect(consoleLogSpy).toHaveBeenCalledWith("HAP-NodeJS WARNING: The accessory 'displayName' is getting published with the characteristic 'name' not following HomeKit naming rules (''bad name'). Use only alphanumeric, space, and apostrophe characters, start and end with an alphabetic or numeric character, and don't include emojis. This might prevent the accessory from being added to the Home App or leading to the accessory being unresponsive!");
});

test("Accessory Name containing '", async () => {
checkName("displayName", "name", "bad ' name");

expect(consoleLogSpy).toBeCalledTimes(0);
expect(consoleLogSpy).toHaveBeenCalledTimes(0);
// eslint-disable-next-line max-len
// expect(consoleLogSpy).toHaveBeenCalledWith("HAP-NodeJS WARNING: The accessory 'displayName' is getting published with the characteristic 'name' not following HomeKit naming rules ('bad name!'). Use only alphanumeric, space, and apostrophe characters, start and end with an alphabetic or numeric character, and don't include emojis. This might prevent the accessory from being added to the Home App or leading to the accessory being unresponsive!");
});
Expand Down
7 changes: 5 additions & 2 deletions src/lib/util/checkName.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@

// 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 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
const pattern = !validHK.test(value) ? "doesn't have only letter, numbers, apostrophe, or dash"
: !startWith.test(value) ? "doesn't start with letter or number,"
: !endWith.test(value) ? "doesn't end with letter or number," : "-";

if (!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 + "'). " +
name + "'" + " not following HomeKit naming rules ('" + value + "', " + " with a pattern that'" + pattern + "'." +
"Use only alphanumeric, space, and apostrophe characters, start and end with an alphabetic or numeric character, and don't include emojis. " +
"This might prevent the accessory from being added to the Home App or leading to the accessory being unresponsive!");
}
Expand Down
29 changes: 25 additions & 4 deletions src/lib/util/eventedhttp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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
}
Expand Down

0 comments on commit a12fb8d

Please sign in to comment.