Skip to content

Commit

Permalink
Support random setup codes and saved verifiers
Browse files Browse the repository at this point in the history
commit 3882b2b
Author: Samuel Elliott <samuel@fancy.org.uk>
Date:   Mon Nov 2 21:21:30 2020 +0000

    Fix CI tests

commit 5e06e26
Merge: d2a1fbc 977d5ad
Author: Samuel Elliott <samuel@fancy.org.uk>
Date:   Mon Nov 2 20:52:55 2020 +0000

    Merge remote-tracking branch 'KhaosT/beta' into random-setup-codes

    # Conflicts:
    #	src/lib/Accessory.ts
    #	src/lib/Advertiser.ts
    #	src/lib/HAPServer.ts
    #	src/lib/util/eventedhttp.ts

commit d2a1fbc
Merge: 130d5d6 d70a1ba
Author: Samuel Elliott <samuel@fancy.org.uk>
Date:   Mon Nov 2 19:27:50 2020 +0000

    Merge remote-tracking branch 'KhaosT/master' into random-setup-codes

    # Conflicts:
    #	src/lib/Accessory.ts
    #	src/lib/Advertiser.ts
    #	src/lib/util/eventedhttp.ts

commit 130d5d6
Author: Samuel Elliott <samuel@fancy.org.uk>
Date:   Mon Nov 2 19:18:42 2020 +0000

    Support saved verifiers

commit 60a52f7
Author: Samuel Elliott <samuel@fancy.org.uk>
Date:   Mon Nov 2 18:59:09 2020 +0000

    Move setup ID related functions

commit 0903a20
Author: Samuel Elliott <samuel@fancy.org.uk>
Date:   Mon Nov 2 18:14:55 2020 +0000

    Refactor using async/await

commit 3d9ce22
Author: Samuel Elliott <samuel@fancy.org.uk>
Date:   Mon Nov 2 17:09:46 2020 +0000

    Print a warning when a pair request is rejected due to the attempt limit

commit 5329ff4
Merge: f6c89db 5cacbd4
Author: Samuel Elliott <samuel@fancy.org.uk>
Date:   Mon Nov 2 16:56:24 2020 +0000

    Merge remote-tracking branch 'KhaosT/master' into random-setup-codes

    # Conflicts:
    #	src/CameraCore.ts
    #	src/lib/Accessory.ts
    #	src/lib/HAPServer.ts
    #	src/lib/model/AccessoryInfo.ts
    #	src/lib/util/eventedhttp.ts

commit 977d5ad
Author: Supereg <mail@anderl-bauer.de>
Date:   Tue Oct 20 13:54:59 2020 +0200

    Adjust idle timeout configuration

commit 46c6498
Author: Supereg <mail@anderl-bauer.de>
Date:   Tue Oct 20 13:34:34 2020 +0200

    Adding idle timeout to hap connections

commit 80ef334
Author: Supereg <mail@anderl-bauer.de>
Date:   Tue Oct 20 10:29:11 2020 +0200

    Fixed accessory characteristic-warning event signature

commit 77a2042
Author: Supereg <mail@anderl-bauer.de>
Date:   Tue Oct 20 10:22:01 2020 +0200

    Pass more characteristic warnings through the event system for homebridge

commit a7d2c5b
Author: Supereg <mail@anderl-bauer.de>
Date:   Tue Oct 20 02:21:29 2020 +0200

    Correctly transform 0 and 1 to boolean values

commit 8234e7b
Author: Supereg <mail@anderl-bauer.de>
Date:   Tue Oct 20 02:21:16 2020 +0200

    Force http socket to connect to loopback address

commit 14a6424
Author: Supereg <mail@anderl-bauer.de>
Date:   Tue Oct 20 02:16:56 2020 +0200

    Adding unit tests for net-utils

commit bc24a23
Author: Supereg <mail@anderl-bauer.de>
Date:   Mon Oct 19 15:02:05 2020 +0200

    Only fire characteristic change when value actually changed

commit 0a45bbf
Author: Supereg <mail@anderl-bauer.de>
Date:   Mon Oct 19 02:19:44 2020 +0200

    Removed notify perms from Version characteristic again.
    Additional Authorization should not be added by default.

commit 581298f
Author: Supereg <mail@anderl-bauer.de>
Date:   Mon Oct 19 01:47:41 2020 +0200

    Don't set the value before calling the set handler

commit 9b6a3ce
Author: Supereg <mail@anderl-bauer.de>
Date:   Mon Oct 19 00:29:20 2020 +0200

    Fixed connection debug output

commit 362a5eb
Author: Supereg <mail@anderl-bauer.de>
Date:   Mon Oct 19 00:12:03 2020 +0200

    Use the correct subclass when deserializing characteristics and services from disk

commit 75452d7
Author: Supereg <mail@anderl-bauer.de>
Date:   Sun Oct 18 22:42:31 2020 +0200

    Add deprecated CameraControl service again

commit 1b47a4c
Author: Supereg <mail@anderl-bauer.de>
Date:   Sun Oct 18 20:19:44 2020 +0200

    Adding debug output for current connection state every minute

commit 091e2a4
Author: Supereg <mail@anderl-bauer.de>
Date:   Fri Oct 16 23:23:07 2020 +0200

    Reworked characteristic and service definition generation

commit 5e9d970
Author: Supereg <mail@anderl-bauer.de>
Date:   Wed Oct 14 16:26:17 2020 +0200

    Improve default value handling of AccessoryInformation characteristics
    Removed error thrown when setting undefined

commit 7fde47b
Author: Supereg <mail@anderl-bauer.de>
Date:   Tue Oct 13 23:32:54 2020 +0200

    Improved handling of undefined and null values for AccessoryInformation service

commit 8fe0b15
Author: Supereg <mail@anderl-bauer.de>
Date:   Tue Oct 13 16:39:38 2020 +0200

    Make warnings less dramatic

commit 917fa6a
Author: Supereg <mail@anderl-bauer.de>
Date:   Mon Oct 12 23:24:58 2020 +0200

    Adding ability to track code coverage

commit e329727
Author: Supereg <mail@anderl-bauer.de>
Date:   Mon Oct 12 22:29:22 2020 +0200

    Fixed assertions and tests

commit 9b30452
Author: Supereg <mail@anderl-bauer.de>
Date:   Mon Oct 12 22:25:04 2020 +0200

    Improved some typing. Only assignIds on main accessory

commit c8b5791
Author: Supereg <mail@anderl-bauer.de>
Date:   Mon Oct 12 15:15:17 2020 +0200

    Minor adjustments handling promise errors on characteristic handlers.
    Additionally we added a custom try-catch for the validateInput function to print a more meaningful error message

commit 83804fb
Author: oznu <dev@oz.nu>
Date:   Mon Oct 12 23:48:00 2020 +1100

    Add support for promise based Characteristic setters and getters (homebridge#849)

commit 3f59de2
Author: Supereg <mail@anderl-bauer.de>
Date:   Mon Oct 12 14:39:42 2020 +0200

    Mitigate crash when check accessory configuration and aid/iids aren't set yet

commit 9d63614
Author: Supereg <mail@anderl-bauer.de>
Date:   Fri Oct 9 00:27:08 2020 +0200

    Ignore empty bind option

commit ac57c4d
Author: Supereg <mail@anderl-bauer.de>
Date:   Fri Oct 9 00:09:51 2020 +0200

    Adjust the bind option to always bind on unspecified addresses to keep a socket on the loopback address for config-ui

commit 6f6a971
Author: Supereg <mail@anderl-bauer.de>
Date:   Thu Oct 8 23:26:53 2020 +0200

    Fix event delivery for bridged accessories

commit 0bedbc5
Author: Supereg <mail@anderl-bauer.de>
Date:   Thu Oct 8 18:28:10 2020 +0200

    Prevent that SerialNumber or Model gets a value assigned with length less or equal to 1 character (fixes homebridge#824)

    Otherwise HomeKit will reject the whole accessory!

commit 5f8a827
Author: Supereg <mail@anderl-bauer.de>
Date:   Thu Oct 8 18:05:31 2020 +0200

    Return http error when receiving duplicate values in /characteristics set/get requests

commit 0ac698f
Author: Supereg <mail@anderl-bauer.de>
Date:   Thu Oct 8 17:45:47 2020 +0200

    Mute event notification calls when aid/iid are not yet set
    Catch any errors which may occur when sending events

commit 7073a82
Author: Supereg <mail@anderl-bauer.de>
Date:   Thu Oct 8 05:52:14 2020 +0200

    Fixed bridged accessories not being returned on /accessories request

commit 4a3f9e7
Author: Supereg <mail@anderl-bauer.de>
Date:   Thu Oct 8 05:30:32 2020 +0200

    Fixed adding bridged accessories

commit 7deb450
Author: Supereg <mail@anderl-bauer.de>
Date:   Thu Oct 8 05:20:38 2020 +0200

    Ensure timeouts don't prevent shutdown

commit df0761d
Author: Supereg <mail@anderl-bauer.de>
Date:   Thu Oct 8 05:15:25 2020 +0200

    Boolean values for numeric formats are now properly converted

commit 074ede1
Author: Supereg <mail@anderl-bauer.de>
Date:   Thu Oct 8 05:14:59 2020 +0200

    Debounce current configuration number increments

commit 2d7aaba
Author: Supereg <mail@anderl-bauer.de>
Date:   Thu Oct 8 04:18:42 2020 +0200

    Service code cleanup

commit 7f00b15
Author: Supereg <mail@anderl-bauer.de>
Date:   Thu Oct 8 04:05:54 2020 +0200

    * Reworked input validation for characteristic values and properties
    * Send correct -70410 response when receiving invalid value in request (out of range etc)
    * GET handler is now called on /accessories to have latest value on discover
    * Added more documentation

commit a063bc1
Author: Supereg <mail@anderl-bauer.de>
Date:   Tue Oct 6 16:40:50 2020 +0200

    Fixing tests

commit 50be234
Author: Supereg <mail@anderl-bauer.de>
Date:   Tue Oct 6 16:06:52 2020 +0200

    setValue method will now fire a SET event again

commit e16a3e4
Author: Supereg <mail@anderl-bauer.de>
Date:   Tue Oct 6 01:10:15 2020 +0200

    Fix tests

commit 89ad4ac
Author: Supereg <mail@anderl-bauer.de>
Date:   Tue Oct 6 00:59:29 2020 +0200

    Remove last traces of custom EventEmitter type

commit f908a9e
Author: Supereg <mail@anderl-bauer.de>
Date:   Tue Oct 6 00:28:25 2020 +0200

    Fixed awfully wrong uuids for iOS 14 characteristics and services

commit 73bf81c
Author: Supereg <mail@anderl-bauer.de>
Date:   Tue Oct 6 00:27:56 2020 +0200

    Adding timeouts to SET, GET and image request handlers.
    Some minor code cleanup.

commit 3673c8d
Author: Supereg <mail@anderl-bauer.de>
Date:   Mon Oct 5 19:22:03 2020 +0200

    Adding support for additional authorization data to be checked by custom handler

commit 024b021
Author: Supereg <mail@anderl-bauer.de>
Date:   Mon Oct 5 18:38:23 2020 +0200

    Minor code fixes in the AccessoryLoader

commit 45b63a7
Author: Supereg <mail@anderl-bauer.de>
Date:   Mon Oct 5 18:24:07 2020 +0200

    Some code cleanup regarding the HAPEncryption object

commit 9f3887d
Author: Supereg <mail@anderl-bauer.de>
Date:   Mon Oct 5 18:10:35 2020 +0200

    Properly delay and combine event notifications

commit d765118
Author: Supereg <mail@anderl-bauer.de>
Date:   Mon Oct 5 16:40:40 2020 +0200

    Bump beta to 0.9.0

commit 8f2c80a
Author: Supereg <mail@anderl-bauer.de>
Date:   Mon Oct 5 01:35:39 2020 +0200

    Removed some obsolete @ts-expect-error

commit 2ef51cf
Author: Supereg <mail@anderl-bauer.de>
Date:   Mon Oct 5 01:31:47 2020 +0200

    Major code cleanup in the EventedHTTPServer and HAPServer classes
    Various fixes, improved typing and more robustness

commit 576271b
Author: Supereg <mail@anderl-bauer.de>
Date:   Sat Oct 3 19:05:35 2020 +0200

    Reduce daysUntilStale to 23

commit 2b57017
Author: Supereg <mail@anderl-bauer.de>
Date:   Sat Oct 3 19:03:08 2020 +0200

    Set the tcp_keepalive_time to 5 seconds

commit 8521c69
Author: Supereg <mail@anderl-bauer.de>
Date:   Sat Oct 3 19:02:46 2020 +0200

    Validate controllerKeySalt length before passing it to the DataStream Server

commit bda16db
Author: Supereg <mail@anderl-bauer.de>
Date:   Wed Sep 30 01:54:05 2020 +0200

    Fixed some tests

commit e2ffbd8
Author: Supereg <mail@anderl-bauer.de>
Date:   Wed Sep 30 01:35:11 2020 +0200

    Completely reworked /characteristics
    * Adding support for metadata, events, type, perms query parameters
    * Moving to promises
    * Reworked Characteristic code

commit 1a6d30b
Author: Supereg <mail@anderl-bauer.de>
Date:   Thu Sep 24 00:54:19 2020 +0200

    Minor improvment of removeLinkedService from Service class

commit 62348d3
Author: Supereg <mail@anderl-bauer.de>
Date:   Thu Sep 24 00:54:07 2020 +0200

    Fixed removeLinkedService

commit c06dbb8
Author: Supereg <mail@anderl-bauer.de>
Date:   Wed Sep 23 19:44:40 2020 +0200

    Listen on the loopback interface only for the internal http server

commit b9b95d5
Author: Supereg <mail@anderl-bauer.de>
Date:   Wed Sep 23 19:14:07 2020 +0200

    Fixed: if a service is removed it is now ensured that no existing services still link to that removed service

commit 72baab0
Author: Supereg <mail@anderl-bauer.de>
Date:   Wed Sep 23 18:59:22 2020 +0200

    Throw a proper exception if chacha20-poly1305 cipher isn't found

commit e858e39
Author: Supereg <mail@anderl-bauer.de>
Date:   Wed Sep 23 18:26:16 2020 +0200

    Minor code cleanup

commit 0843e2a
Author: Supereg <mail@anderl-bauer.de>
Date:   Wed Sep 23 17:53:56 2020 +0200

    Introducing new "bind" publish option, in oder to bind/advertise the hap-nodejs to a certain interface(s)/ip address(es)

commit 5eabcf8
Author: Supereg <mail@anderl-bauer.de>
Date:   Mon Sep 21 15:47:18 2020 +0200

    Mitigating warning for memory leak on the UNPAIRED event

commit 1fa08d0
Author: Supereg <mail@anderl-bauer.de>
Date:   Mon Sep 21 15:39:47 2020 +0200

    Add some little deprecation notice

commit 0afceab
Author: Supereg <mail@anderl-bauer.de>
Date:   Mon Sep 21 15:37:38 2020 +0200

    Adding source-map-support for better stack strace translation

commit 8ee8888
Author: Supereg <mail@anderl-bauer.de>
Date:   Mon Sep 21 15:13:30 2020 +0200

    Notify active streaming session that the application is about to exit

commit 059def9
Author: Supereg <mail@anderl-bauer.de>
Date:   Mon Sep 21 14:59:53 2020 +0200

    Updated service and characteristic definitions to latest iOS 14 release

commit eb9dd8a
Author: Supereg <mail@anderl-bauer.de>
Date:   Mon Sep 21 14:56:15 2020 +0200

    Adding version note to some of the latest characteristics and services

commit 52f61fd
Author: Supereg <mail@anderl-bauer.de>
Date:   Mon Sep 21 14:42:07 2020 +0200

    Doing a subnet check as fallback if local interface detection fails for HAP socket

commit 00bf51d
Author: Supereg <mail@anderl-bauer.de>
Date:   Mon Sep 21 14:20:30 2020 +0200

    Mark the start of beta 0.8.3

commit f6c89db
Author: Samuel Elliott <samuel@fancy.org.uk>
Date:   Sun Apr 12 02:42:33 2020 +0100

    Redo flag checks closer to the spec., add initial transient pair setup support

commit a9dc408
Author: Samuel Elliott <samuel@fancy.org.uk>
Date:   Sun Apr 12 00:54:32 2020 +0100

    Fix checking if another client is trying to pair

commit c436563
Merge: 4abd809 9e86970
Author: Samuel Elliott <samuel@fancy.org.uk>
Date:   Sat Apr 11 19:07:53 2020 +0100

    Merge remote-tracking branch 'KhaosT/master' into random-setup-codes

    # Conflicts:
    #	src/lib/Accessory.ts
    #	src/lib/HAPServer.ts

commit 4abd809
Merge: b4d95e8 6fbafa8
Author: Samuel Elliott <samuel@fancy.org.uk>
Date:   Thu Nov 28 14:07:31 2019 +0000

    Merge remote-tracking branch 'refs/remotes/KhaosT/master' into random-setup-codes

    # Conflicts:
    #	src/lib/Accessory.ts
    #	src/lib/gen/importAsClasses.ts

commit b4d95e8
Merge: f5e303f 50ac924
Author: Samuel Elliott <samuel@fancy.org.uk>
Date:   Sun Nov 3 20:02:45 2019 +0000

    Merge remote-tracking branch 'KhaosT/master' into random-setup-codes

    # Conflicts:
    #	src/lib/HAPServer.ts
    #	src/lib/util/eventedhttp.ts

commit f5e303f
Author: Samuel Elliott <samuel@fancy.org.uk>
Date:   Mon Oct 28 14:06:50 2019 +0000

    Use random setup codes by default and add pair setup start/finish events

commit 0850c5c
Author: Samuel Elliott <samuel@fancy.org.uk>
Date:   Sun Oct 27 22:04:44 2019 +0000

    Use random setup codes in Bridged/CameraCore.ts and only for accessories without a setup code in Core.ts

commit 6830baa
Author: Samuel Elliott <samuel@fancy.org.uk>
Date:   Sun Oct 27 19:57:22 2019 +0000

    Add a function to generate a random setup code

commit a6a4810
Author: Samuel Elliott <samuel@fancy.org.uk>
Date:   Sun Oct 27 19:53:31 2019 +0000

    Support using a random setup code

commit 322baca
Author: Samuel Elliott <samuel@fancy.org.uk>
Date:   Sun Oct 27 18:47:32 2019 +0000

    Fix pairing, unpairing and pairing again without restarting

commit 5babe40
Author: Samuel Elliott <samuel@fancy.org.uk>
Date:   Sun Oct 27 18:02:49 2019 +0000

    Only allow a single pair request
  • Loading branch information
samuelthomas2774 authored and Supereg committed Apr 26, 2021
1 parent 7cf7397 commit 436be7b
Show file tree
Hide file tree
Showing 13 changed files with 8,135 additions and 117 deletions.
7,771 changes: 7,770 additions & 1 deletion package-lock.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion package.json
Expand Up @@ -49,6 +49,8 @@
"README.md",
"LICENSE",
"dist",
"!dist/accessories",
"!dist/scripts",
"@types"
],
"dependencies": {
Expand All @@ -69,9 +71,9 @@
"@types/node": "^10.17.58",
"@typescript-eslint/eslint-plugin": "^4.17.0",
"@typescript-eslint/parser": "^4.17.0",
"eslint": "^7.24.0",
"commander": "^6.2.1",
"escape-html": "^1.0.3",
"eslint": "^7.24.0",
"jest": "^26.6.3",
"rimraf": "^3.0.2",
"semver": "^7.3.5",
Expand Down
3 changes: 1 addition & 2 deletions src/BridgedCore.ts
Expand Up @@ -2,7 +2,7 @@ import path from 'path';

import storage from 'node-persist';

import { Accessory, AccessoryEventTypes, AccessoryLoader, Bridge, Categories, uuid, VoidCallback } from './';
import { Accessory, AccessoryEventTypes, AccessoryLoader, Bridge, Categories, uuid, generateSetupCode, VoidCallback } from './';

console.log("HAP-NodeJS starting...");

Expand Down Expand Up @@ -34,7 +34,6 @@ accessories.forEach((accessory: Accessory) => {
bridge.publish({
username: "CC:22:3D:E3:CE:F6",
port: 51826,
pincode: "031-45-154",
category: Categories.BRIDGE
});

Expand Down
8 changes: 2 additions & 6 deletions src/Core.ts
Expand Up @@ -2,7 +2,8 @@ import path from 'path';

import storage from 'node-persist';

import { AccessoryLoader } from './';
import { AccessoryLoader, generateSetupCode } from './';
import { NodeCallback } from './types';

console.log("HAP-NodeJS starting...");

Expand All @@ -28,11 +29,6 @@ accessories.forEach((accessory) => {
throw new Error("Username not found on accessory '" + accessory.displayName +
"'. Core.js requires all accessories to define a unique 'username' property.");

// @ts-ignore
if (!accessory.pincode)
throw new Error("Pincode not found on accessory '" + accessory.displayName +
"'. Core.js requires all accessories to define a 'pincode' property.");

// publish this Accessory on the local network
accessory.publish({
port: targetPort++,
Expand Down
2 changes: 2 additions & 0 deletions src/index.ts
Expand Up @@ -22,6 +22,8 @@ export * from './lib/controller';

export * from './lib/util/clone';
export * from './lib/util/once';
export * from './lib/util/setupcode';
export * from './lib/util/setupid';
export * from './lib/util/tlv';
export * from './lib/util/hapStatusError';
export * from './lib/util/color-utils';
Expand Down
101 changes: 49 additions & 52 deletions src/lib/Accessory.ts
Expand Up @@ -28,6 +28,7 @@ import {
Nullable,
VoidCallback,
WithUUID,
NodeCallback,
} from '../types';
import { Advertiser, AdvertiserEvent, BonjourHAPAdvertiser, CiaoAdvertiser } from './Advertiser';
// noinspection JSDeprecatedSymbols
Expand Down Expand Up @@ -60,11 +61,12 @@ import {
IdentifyCallback,
ListPairingsCallback,
PairCallback,
PairIdentity,
ReadCharacteristicsCallback,
RemovePairingCallback,
ResourceRequestCallback,
TLVErrorCode,
WriteCharacteristicsCallback
WriteCharacteristicsCallback,
} from './HAPServer';
import { AccessoryInfo, PermissionTypes } from './model/AccessoryInfo';
import { ControllerStorage } from "./model/ControllerStorage";
Expand All @@ -75,7 +77,10 @@ import { EventName, HAPConnection, HAPUsername } from "./util/eventedhttp";
import { formatOutgoingCharacteristicValue } from "./util/request-util";
import * as uuid from "./util/uuid";
import { toShortForm } from "./util/uuid";
import { generateSetupId, generateSetupUri } from './util/setupid';
import { generateSetupCode } from './util/setupcode';
import Timeout = NodeJS.Timeout;
import { Identity } from 'fast-srp-hap';

const debug = createDebug('HAP-NodeJS:Accessory');
const MAX_ACCESSORIES = 149; // Maximum number of bridged accessories per bridge.
Expand Down Expand Up @@ -178,7 +183,9 @@ export type CharacteristicEvents = Record<string, any>;

export interface PublishInfo {
username: MacAddress;
pincode: HAPPincode;
pincode?: HAPPincode
| ((callback: NodeCallback<string>, connection: HAPConnection) => void)
| {salt: Buffer; verifier: Buffer};
/**
* Specify the category for the HomeKit accessory.
* The category is used only in the mdns advertisement and specifies the devices type
Expand Down Expand Up @@ -293,6 +300,8 @@ const enum WriteRequestState {
TIMED_WRITE_REJECTED
}

export type SetupCode = Identity & {setupcode: string | null; setupuri: string | null};

// noinspection JSUnusedGlobalSymbols
/**
* @deprecated Use AccessoryEventTypes instead
Expand All @@ -310,6 +319,8 @@ export const enum AccessoryEventTypes {
*/
IDENTIFY = "identify",
LISTENING = "listening",
PAIR_SETUP_STARTED = 'pair-setup-started',
PAIR_SETUP_FINISHED = 'pair-setup-finished',
SERVICE_CONFIGURATION_CHANGE = "service-configurationChange",
/**
* Emitted after a change in the value of one of the provided Service's Characteristics.
Expand All @@ -328,6 +339,9 @@ export declare interface Accessory {
on(event: "service-configurationChange", listener: (change: ServiceConfigurationChange) => void): this;
on(event: "service-characteristic-change", listener: (change: AccessoryCharacteristicChange) => void): this;

on(event: "pair-setup-started", listener: (setupcode: SetupCode, connection: HAPConnection) => void): this;
on(event: "pair-setup-finished", listener: (err: Error | null, clientUsername: string | null, connection: HAPConnection) => void): this;

on(event: "paired", listener: () => void): this;
on(event: "unpaired", listener: () => void): this;

Expand All @@ -340,6 +354,9 @@ export declare interface Accessory {
emit(event: "service-configurationChange", change: ServiceConfigurationChange): boolean;
emit(event: "service-characteristic-change", change: AccessoryCharacteristicChange): boolean;

emit(event: "pair-setup-started", setupcode: SetupCode, connection: HAPConnection): boolean;
emit(event: "pair-setup-finished", err: Error | null, clientUsername: string | null, connection: HAPConnection): boolean;

emit(event: "paired"): boolean;
emit(event: "unpaired"): boolean;

Expand Down Expand Up @@ -880,39 +897,6 @@ export class Accessory extends EventEmitter {
});
}

setupURI(): string {
if (this._setupURI) {
return this._setupURI;
}

const buffer = Buffer.alloc(8);
const setupCode = this._accessoryInfo && parseInt(this._accessoryInfo.pincode.replace(/-/g, ''), 10);

let value_low = setupCode!;
const value_high = this._accessoryInfo && this._accessoryInfo.category >> 1;

value_low |= 1 << 28; // Supports IP;

buffer.writeUInt32BE(value_low, 4);

if (this._accessoryInfo && this._accessoryInfo.category & 1) {
buffer[4] = buffer[4] | 1 << 7;
}

buffer.writeUInt32BE(value_high!, 0);

let encodedPayload = (buffer.readUInt32BE(4) + (buffer.readUInt32BE(0) * Math.pow(2, 32))).toString(36).toUpperCase();

if (encodedPayload.length != 9) {
for (let i = 0; i <= 9 - encodedPayload.length; i++) {
encodedPayload = "0" + encodedPayload;
}
}

this._setupURI = "X-HM://" + encodedPayload + this._setupID;
return this._setupURI;
}

/**
* This method is called right before the accessory is published. It should be used to check for common
* mistakes in Accessory structured, which may lead to HomeKit rejecting the accessory when pairing.
Expand Down Expand Up @@ -1080,8 +1064,9 @@ export class Accessory extends EventEmitter {
* @param allowInsecureRequest - Will allow unencrypted and unauthenticated access to the http server
* @param {string} info.username - The "username" (formatted as a MAC address - like "CC:22:3D:E3:CE:F6") of
* this Accessory. Must be globally unique from all Accessories on your local network.
* @param {string} info.pincode - The 8-digit pincode for clients to use when pairing this Accessory. Must be formatted
* as a string like "031-45-154".
* @param {string|function} info.pincode - The 8-digit pincode for clients to use when pairing this Accessory. Must
* be formatted as a string like "031-45-154". You can also provide a function that
* generates a random setup code and presents it to the user.
* @param {string} info.category - One of the values of the Accessory.Category enum, like Accessory.Category.SWITCH.
* This is a hint to iOS clients about what "type" of Accessory this represents, so
* that for instance an appropriate icon can be drawn for the user while adding a
Expand Down Expand Up @@ -1132,7 +1117,7 @@ export class Accessory extends EventEmitter {
if (info.setupID) {
this._setupID = info.setupID;
} else if (this._accessoryInfo.setupID === undefined || this._accessoryInfo.setupID === "") {
this._setupID = Accessory._generateSetupID();
this._setupID = generateSetupId();
} else {
this._setupID = this._accessoryInfo.setupID;
}
Expand All @@ -1143,7 +1128,7 @@ export class Accessory extends EventEmitter {
this._accessoryInfo.displayName = this.displayName;
this._accessoryInfo.model = this.getService(Service.AccessoryInformation)!.getCharacteristic(Characteristic.Model).value as string;
this._accessoryInfo.category = info.category || Categories.OTHER;
this._accessoryInfo.pincode = info.pincode;
this._accessoryInfo.pincode = info.pincode && typeof info.pincode !== 'function' ? info.pincode : null;
this._accessoryInfo.save();

// create our IdentifierCache so we can provide clients with stable aid/iid's
Expand Down Expand Up @@ -1218,6 +1203,8 @@ export class Accessory extends EventEmitter {
this._server.allowInsecureRequest = !!allowInsecureRequest;
this._server.on(HAPServerEventTypes.LISTENING, this.onListening.bind(this));
this._server.on(HAPServerEventTypes.IDENTIFY, this.identificationRequest.bind(this, false));
this._server.on(HAPServerEventTypes.PAIR_SETUP_STARTED, this._handlePairSetupStarted.bind(this));
this._server.on(HAPServerEventTypes.PAIR_SETUP_FINISHED, this._handlePairSetupFinished.bind(this));
this._server.on(HAPServerEventTypes.PAIR, this.handleInitialPairSetupFinished.bind(this));
this._server.on(HAPServerEventTypes.ADD_PAIRING, this.handleAddPairing.bind(this));
this._server.on(HAPServerEventTypes.REMOVE_PAIRING, this.handleRemovePairing.bind(this));
Expand All @@ -1228,6 +1215,12 @@ export class Accessory extends EventEmitter {
this._server.on(HAPServerEventTypes.CONNECTION_CLOSED, this.handleHAPConnectionClosed.bind(this));
this._server.on(HAPServerEventTypes.REQUEST_RESOURCE, this.handleResource.bind(this));

if (typeof info.pincode === 'function') {
this._server.on(HAPServerEventTypes.GENERATE_SETUP_CODE, info.pincode);
} else if (typeof info.pincode !== 'string' && typeof info.pincode !== 'object') {
this._server.on(HAPServerEventTypes.GENERATE_SETUP_CODE, generateSetupCode);
}

this._server.listen(info.port, parsed.serverAddress);
}

Expand Down Expand Up @@ -1294,6 +1287,23 @@ export class Accessory extends EventEmitter {
this.emit(AccessoryEventTypes.LISTENING, port, hostname);
}

/** Called when starting the pair setup process after a setup code has been generated */
private _handlePairSetupStarted(i: PairIdentity, connection: HAPConnection) {
if (this.listenerCount(AccessoryEventTypes.PAIR_SETUP_STARTED)) {
if (!this._setupID) this._setupID = generateSetupId();
const setupuri = i.setupcode ? generateSetupUri(i.setupcode, this._setupID, this.category) : null;
this.emit(AccessoryEventTypes.PAIR_SETUP_STARTED, {...i, setupuri}, connection);
} else if (!this._accessoryInfo!.pincode) {
// If we're using random setup codes and there's nothing listening for the setup code print it to the console
console.log('[%s] Received pair request from %s', this.displayName, connection.remoteAddress, i.setupcode);
}
}

/** Called when the pair setup process has finished with the error or paired client username */
private _handlePairSetupFinished(err: Nullable<Error>, clientUsername: Nullable<string>, connection: HAPConnection) {
this.emit(AccessoryEventTypes.PAIR_SETUP_FINISHED, err, clientUsername, connection);
}

private handleInitialPairSetupFinished(username: string, publicKey: Buffer, callback: PairCallback): void {
debug("[%s] Paired with client %s", this.displayName, username);

Expand Down Expand Up @@ -1917,19 +1927,6 @@ export class Accessory extends EventEmitter {
});
}

private static _generateSetupID(): string {
const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const max = chars.length;
let setupID = '';

for (let i = 0; i < 4; i++) {
const index = Math.floor(Math.random() * max)
setupID += chars.charAt(index);
}

return setupID;
}

// serialization and deserialization functions, mainly designed for homebridge to create a json copy to store on disk
public static serialize(accessory: Accessory): SerializedAccessory {
const json: SerializedAccessory = {
Expand Down
12 changes: 3 additions & 9 deletions src/lib/Advertiser.ts
Expand Up @@ -10,9 +10,9 @@ import ciao, {
import { InterfaceName, IPAddress } from "@homebridge/ciao/lib/NetworkManager";
import assert from "assert";
import bonjour, { BonjourHAP, BonjourHAPService, MulticastOptions } from "bonjour-hap";
import crypto from 'crypto';
import { EventEmitter } from "events";
import { AccessoryInfo } from './model/AccessoryInfo';
import { generateSetupHash } from "./util/setupid";

/**
* This enum lists all bitmasks for all known status flags.
Expand Down Expand Up @@ -101,7 +101,7 @@ export class CiaoAdvertiser extends EventEmitter implements Advertiser {
constructor(accessoryInfo: AccessoryInfo, responderOptions?: MDNSServerOptions, serviceOptions?: ServiceNetworkOptions) {
super();
this.accessoryInfo = accessoryInfo;
this.setupHash = CiaoAdvertiser.computeSetupHash(accessoryInfo);
this.setupHash = generateSetupHash(this.accessoryInfo.username, this.accessoryInfo.setupID).toString('base64');

this.responder = ciao.getResponder({
...responderOptions
Expand Down Expand Up @@ -157,12 +157,6 @@ export class CiaoAdvertiser extends EventEmitter implements Advertiser {
};
}

static computeSetupHash(accessoryInfo: AccessoryInfo): string {
const hash = crypto.createHash('sha512');
hash.update(accessoryInfo.setupID + accessoryInfo.username.toUpperCase());
return hash.digest().slice(0, 4).toString('base64');
}

public static ff(...flags: PairingFeatureFlag[]): number {
let value = 0;
flags.forEach(flag => value |= flag);
Expand Down Expand Up @@ -195,7 +189,7 @@ export class BonjourHAPAdvertiser extends EventEmitter implements Advertiser {
constructor(accessoryInfo: AccessoryInfo, responderOptions?: MulticastOptions, serviceOptions?: ServiceNetworkOptions) {
super();
this.accessoryInfo = accessoryInfo;
this.setupHash = CiaoAdvertiser.computeSetupHash(accessoryInfo);
this.setupHash = generateSetupHash(this.accessoryInfo.username, this.accessoryInfo.setupID).toString('base64');
this.serviceOptions = serviceOptions;

this.bonjour = bonjour(responderOptions);
Expand Down

0 comments on commit 436be7b

Please sign in to comment.