Skip to content

Commit

Permalink
Print a warning when a pair request is rejected due to the attempt limit
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelthomas2774 committed Nov 2, 2020
1 parent 5329ff4 commit 3d9ce22
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 20 deletions.
1 change: 0 additions & 1 deletion src/lib/Accessory.ts
Expand Up @@ -40,7 +40,6 @@ import {
CameraRTPStreamManagement,
} from "./gen/HomeKit";
import { ControllerStorage } from "./model/ControllerStorage";
import { builtinModules } from 'module';

const debug = createDebug('HAP-NodeJS:Accessory');
const MAX_ACCESSORIES = 149; // Maximum number of bridged accessories per bridge.
Expand Down
5 changes: 2 additions & 3 deletions src/lib/HAPServer.ts
Expand Up @@ -372,6 +372,7 @@ export class HAPServer extends EventEmitter<Events> {
}

if (this.unsuccessfulPairAttempts > 100) {
debug("[%s] Pair request from %s was rejected as there has been 100 unsuccessful pair attempts", this.accessoryInfo.username, session._connection.remoteAddress);
response.writeHead(200, {"Content-Type": "application/pairing+tlv8"});
response.end(tlv.encode(TLVValues.STATE, States.M2, TLVValues.ERROR_CODE, Codes.MAX_TRIES));
return;
Expand Down Expand Up @@ -403,8 +404,8 @@ export class HAPServer extends EventEmitter<Events> {
// M1 + M2
_handlePairStepOne = (request: IncomingMessage, response: ServerResponse, session: Session, objects: Record<number, Buffer>) => {
debug("[%s] Pair step 1/5", this.accessoryInfo.username);
const salt = crypto.randomBytes(16, );

const salt = crypto.randomBytes(16);
const srpParams = SRP.params.hap;

if (objects[TLVValues.METHOD][0] !== Methods.PAIR_SETUP) {
Expand All @@ -427,7 +428,6 @@ export class HAPServer extends EventEmitter<Events> {
response.writeHead(200, {"Content-Type": "application/pairing+tlv8"});
response.end(tlv.encode(TLVValues.STATE, States.M2, TLVValues.ERROR_CODE, Codes.UNAVAILABLE));
this._pairing = null;
return;
}

SRP.genKey(32).then(key => {
Expand All @@ -448,7 +448,6 @@ export class HAPServer extends EventEmitter<Events> {
response.writeHead(200, {"Content-Type": "application/pairing+tlv8"});
response.end(tlv.encode(TLVValues.STATE, States.M2, TLVValues.ERROR_CODE, Codes.UNKNOWN));
this._pairing = null;
return;
});
}), session);
} else if ((split && this._setupCode) || this.accessoryInfo.pincode) {
Expand Down
36 changes: 20 additions & 16 deletions src/lib/util/eventedhttp.ts
Expand Up @@ -263,7 +263,9 @@ export class Session extends EventEmitter<HAPSessionEventMap> {
class EventedHTTPServerConnection extends EventEmitter<Events> {
readonly server: EventedHTTPServer;
sessionID: SessionIdentifier;
_remoteAddress: string;
readonly remoteAddress: string;
readonly remotePort: number;
readonly remoteFamily: string;
_pendingClientSocketData: Nullable<Buffer>;
_fullySetup: boolean;
_writingResponse: boolean;
Expand All @@ -281,7 +283,9 @@ class EventedHTTPServerConnection extends EventEmitter<Events> {

this.server = server;
this.sessionID = uuid.generate(clientSocket.remoteAddress + ':' + clientSocket.remotePort);
this._remoteAddress = clientSocket.remoteAddress!; // cache because it becomes undefined in 'onClientSocketClose'
this.remoteAddress = clientSocket.remoteAddress!; // cache because it becomes undefined in 'onClientSocketClose'
this.remotePort = clientSocket.remotePort!;
this.remoteFamily = clientSocket.remoteFamily!;
this._pendingClientSocketData = Buffer.alloc(0); // data received from client before HTTP proxy is fully setup
this._fullySetup = false; // true when we are finished establishing connections
this._writingResponse = false; // true while we are composing an HTTP response (so events can wait)
Expand All @@ -306,7 +310,7 @@ class EventedHTTPServerConnection extends EventEmitter<Events> {
this._session = new Session(this);
// a collection of event names subscribed to by this connection
this._events = {}; // this._events[eventName] = true (value is arbitrary, but must be truthy)
debug("[%s] New connection from client", this._remoteAddress);
debug("[%s] New connection from client", this.remoteAddress);
}

get connected() {
Expand All @@ -320,10 +324,10 @@ class EventedHTTPServerConnection extends EventEmitter<Events> {
}
// does this connection's 'events' object match the excludeEvents object? if so, don't send the event.
if (excludeEvents === this._events) {
debug("[%s] Muting event '%s' notification for this connection since it originated here.", this._remoteAddress, event);
debug("[%s] Muting event '%s' notification for this connection since it originated here.", this.remoteAddress, event);
return;
}
debug("[%s] Sending HTTP event '%s' with data: %s", this._remoteAddress, event, data.toString('utf8'));
debug("[%s] Sending HTTP event '%s' with data: %s", this.remoteAddress, event, data.toString('utf8'));
// ensure data is a Buffer
if (typeof data === 'string') {
data = Buffer.from(data);
Expand Down Expand Up @@ -365,7 +369,7 @@ class EventedHTTPServerConnection extends EventEmitter<Events> {
}

// an existing HTTP response was finished, so let's flush our pending event buffer if necessary!
debug("[%s] Writing pending HTTP event data", this._remoteAddress);
debug("[%s] Writing pending HTTP event data", this.remoteAddress);
this._pendingEventData.forEach(event => {
const encrypted = {data: null};
this.emit(EventedHTTPServerEvents.ENCRYPT, event, encrypted, this._session);
Expand All @@ -384,7 +388,7 @@ class EventedHTTPServerConnection extends EventEmitter<Events> {
// Called only once right after constructor finishes
_onHttpServerListening = () => {
this._httpPort = (this._httpServer.address() as AddressInfo).port;
debug("[%s] HTTP server listening on port %s", this._remoteAddress, this._httpPort);
debug("[%s] HTTP server listening on port %s", this.remoteAddress, this._httpPort);
// closes before this are due to retrying listening, which don't need to be handled
this._httpServer.on('close', this._onHttpServerClose);
// now we can establish a connection to this running HTTP server for proxying data
Expand Down Expand Up @@ -420,7 +424,7 @@ class EventedHTTPServerConnection extends EventEmitter<Events> {

if (decrypted.error) {
// decryption and/or verification failed, disconnect the client
debug("[%s] Error occurred trying to decrypt incoming packet: %s", this._remoteAddress, decrypted.error.message);
debug("[%s] Error occurred trying to decrypt incoming packet: %s", this.remoteAddress, decrypted.error.message);
this.close();
} else {
if (decrypted.data) {
Expand Down Expand Up @@ -456,7 +460,7 @@ class EventedHTTPServerConnection extends EventEmitter<Events> {

// Our internal HTTP Server has been closed (happens after we call this._httpServer.close() below)
_onServerSocketClose = () => {
debug("[%s] HTTP connection was closed", this._remoteAddress);
debug("[%s] HTTP connection was closed", this.remoteAddress);
// make sure the iOS side is closed as well
this._clientSocket.destroy();
// we only support a single long-lived connection to our internal HTTP server. Since it's closed,
Expand All @@ -466,16 +470,16 @@ class EventedHTTPServerConnection extends EventEmitter<Events> {

// Our internal HTTP Server has been closed (happens after we call this._httpServer.close() below)
_onServerSocketError = (err: Error) => {
debug("[%s] HTTP connection error: ", this._remoteAddress, err.message);
debug("[%s] HTTP connection error: ", this.remoteAddress, err.message);
// _onServerSocketClose will be called next
}

_onHttpServerRequest = (request: IncomingMessage, response: OutgoingMessage) => {
debug("[%s] HTTP request: %s", this._remoteAddress, request.url);
debug("[%s] HTTP request: %s", this.remoteAddress, request.url);

// sign up to know when the response is ended, so we can safely send EVENT responses
response.on('finish', () => {
debug("[%s] HTTP Response is finished", this._remoteAddress);
debug("[%s] HTTP Response is finished", this.remoteAddress);
this._writingResponse = false;
this._sendPendingEvents();
});
Expand All @@ -484,28 +488,28 @@ class EventedHTTPServerConnection extends EventEmitter<Events> {
}

_onHttpServerClose = () => {
debug("[%s] HTTP server was closed", this._remoteAddress);
debug("[%s] HTTP server was closed", this.remoteAddress);
// notify listeners that we are completely closed
this.emit(EventedHTTPServerEvents.CLOSE, this._events);
}

_onHttpServerError = (err: Error & { code?: string }) => {
debug("[%s] HTTP server error: %s", this._remoteAddress, err.message);
debug("[%s] HTTP server error: %s", this.remoteAddress, err.message);
if (err.code === 'EADDRINUSE') {
this._httpServer.close();
this._httpServer.listen(0);
}
}

_onClientSocketClose = () => {
debug("[%s] Client connection closed", this._remoteAddress);
debug("[%s] Client connection closed", this.remoteAddress);
// shutdown the other side
this._serverSocket && this._serverSocket.destroy();
this._session._connectionDestroyed();
}

_onClientSocketError = (err: Error) => {
debug("[%s] Client connection error: %s", this._remoteAddress, err.message);
debug("[%s] Client connection error: %s", this.remoteAddress, err.message);
// _onClientSocketClose will be called next
}
}

0 comments on commit 3d9ce22

Please sign in to comment.