Skip to content

Commit 009cb81

Browse files
committed
* The hostname in setSecurityParams is now treated like the one given to tryToConnect (fixes the issue mentioned in #30)
* added tests for `getConnection`
1 parent 025cc6d commit 009cb81

6 files changed

Lines changed: 84 additions & 12 deletions

File tree

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,9 @@ To only reset connections and requests for a specific hostname, pass the hostnam
145145

146146
## Changelog
147147

148+
#### 0.5.4 (2018-02-13)
149+
* (AlCalzone) The hostname in `setSecurityParams` is now treated like the one given to `tryToConnect` (fixes the issue mentioned in #30)
150+
148151
#### 0.5.3 (2018-02-07)
149152
* (AlCalzone) Attempt to fix `TypeError: generator already running` in ioBroker.tradfri
150153

build/CoapClient.d.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -157,11 +157,6 @@ export declare class CoapClient {
157157
* @param target The target to connect to. Must be a string, NodeJS.Url or Origin and has to contain the protocol, host and port.
158158
*/
159159
static tryToConnect(target: string | nodeUrl.Url | Origin): Promise<boolean>;
160-
/**
161-
* Establishes a new or retrieves an existing connection to the given origin
162-
* @param origin - The other party
163-
*/
164-
private static getConnection(origin);
165160
private static workOffPendingConnections();
166161
/**
167162
* Establishes or retrieves a socket that can be used to send to and receive data from the given origin

build/CoapClient.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,19 @@ function validateBlockSize(size) {
9696
return false;
9797
return true;
9898
}
99+
// Since coaps:// urls are parsed by the url package, the contained hostname is normalized.
100+
// This function applies the same transformation to any given hostname. Fixes the issue mentioned in #30
101+
/**
102+
* Normalizes a hostname so it matches between `setSecurityParameters` and `connect`
103+
* @param hostname The hostname to normalize
104+
*/
105+
function normalizeHostname(hostname) {
106+
// make sure noone gave us a full URI
107+
if (!hostname.startsWith("coap://") && !hostname.startsWith("coaps://")) {
108+
hostname = `coaps://${hostname}`;
109+
}
110+
return nodeUrl.parse(hostname).hostname;
111+
}
99112
/**
100113
* provides methods to access CoAP server resources
101114
*/
@@ -104,6 +117,7 @@ class CoapClient {
104117
* Sets the security params to be used for the given hostname
105118
*/
106119
static setSecurityParams(hostname, params) {
120+
hostname = normalizeHostname(hostname);
107121
CoapClient.dtlsParams.set(hostname, params);
108122
}
109123
/**
@@ -836,6 +850,7 @@ class CoapClient {
836850
/**
837851
* Establishes a new or retrieves an existing connection to the given origin
838852
* @param origin - The other party
853+
* @internal
839854
*/
840855
static getConnection(origin) {
841856
const originString = origin.toString();
@@ -920,8 +935,6 @@ class CoapClient {
920935
// simply return a normal udp socket
921936
return Promise.resolve(new SocketWrapper_1.SocketWrapper(dgram.createSocket("udp4")));
922937
case "coaps:":
923-
// return a promise we resolve as soon as the connection is secured
924-
const ret = DeferredPromise_1.createDeferredPromise();
925938
// try to find security parameters
926939
if (!CoapClient.dtlsParams.has(origin.hostname)) {
927940
return Promise.reject(new Error(`No security parameters given for the resource at ${origin.toString()}`));
@@ -931,6 +944,8 @@ class CoapClient {
931944
address: origin.hostname,
932945
port: origin.port,
933946
}, CoapClient.dtlsParams.get(origin.hostname));
947+
// return a promise we resolve as soon as the connection is secured
948+
const ret = DeferredPromise_1.createDeferredPromise();
934949
// try connecting
935950
const onConnection = () => {
936951
debug("successfully created socket for origin " + origin.toString());

package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "node-coap-client",
3-
"version": "0.5.3",
3+
"version": "0.5.4",
44
"description": "Clientside implementation of the CoAP protocol with DTLS support.",
55
"keywords": [
66
"coap",
@@ -38,7 +38,7 @@
3838
},
3939
"dependencies": {
4040
"debug": "^3.1.0",
41-
"node-dtls-client": "^0.3.0"
41+
"node-dtls-client": "^0.3.1"
4242
},
4343
"engines": {
4444
"node": ">= 6.0.0"
@@ -55,6 +55,9 @@
5555
"include": [
5656
"src/**/*.ts"
5757
],
58+
"exclude": [
59+
"**/*.test.ts"
60+
],
5861
"extension": [
5962
".ts"
6063
],

src/CoapClient.test.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// tslint:disable:no-console
2+
// tslint:disable:no-unused-expression
3+
import { expect, should, use } from "chai";
4+
import * as chaiAsPromised from "chai-as-promised";
5+
6+
before(() => {
7+
use(chaiAsPromised);
8+
should();
9+
});
10+
11+
import { CoapClient as coap } from "./CoapClient";
12+
import { Origin } from "./lib/Origin";
13+
14+
describe("CoapClient Tests =>", () => {
15+
16+
coap.setSecurityParams("does-not-exist", {
17+
psk: { IDENTITY: "FOO" },
18+
});
19+
const correctOrigin = new Origin("coaps:", "does-not-exist", 5684);
20+
// tslint:disable-next-line:variable-name
21+
const correctOrigin_wrongCasing = new Origin("coaps:", "does-NOT-exist", 5684);
22+
const wrongOrigin = new Origin("coaps:", "does-not-exist2", 5684);
23+
24+
it("connecting to a non-existing endpoint should fail with ENOTFOUND or DTLS timeout", function() {
25+
this.timeout(10000);
26+
return coap.getConnection(correctOrigin).should.be.rejectedWith(/(ENOTFOUND)|(DTLS handshake timed out)/);
27+
});
28+
it("the hostname should not be case-sensitive", function() {
29+
this.timeout(10000);
30+
// we test against a non-existing endpoint, so ENOTFOUND should be thrown but not "No security parameters given"
31+
return coap.getConnection(correctOrigin_wrongCasing).should.be.rejectedWith(/(ENOTFOUND)|(DTLS handshake timed out)/);
32+
});
33+
it("missing security params should fail the connection with the correct message", function() {
34+
this.timeout(10000);
35+
return coap.getConnection(wrongOrigin).should.be.rejectedWith("No security parameters");
36+
});
37+
38+
});

src/CoapClient.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,20 @@ function validateBlockSize(size: number): boolean {
164164
return true;
165165
}
166166

167+
// Since coaps:// urls are parsed by the url package, the contained hostname is normalized.
168+
// This function applies the same transformation to any given hostname. Fixes the issue mentioned in #30
169+
/**
170+
* Normalizes a hostname so it matches between `setSecurityParameters` and `connect`
171+
* @param hostname The hostname to normalize
172+
*/
173+
function normalizeHostname(hostname: string): string {
174+
// make sure noone gave us a full URI
175+
if (!hostname.startsWith("coap://") && !hostname.startsWith("coaps://")) {
176+
hostname = `coaps://${hostname}`;
177+
}
178+
return nodeUrl.parse(hostname).hostname;
179+
}
180+
167181
/**
168182
* provides methods to access CoAP server resources
169183
*/
@@ -192,6 +206,7 @@ export class CoapClient {
192206
* Sets the security params to be used for the given hostname
193207
*/
194208
public static setSecurityParams(hostname: string, params: SecurityParameters) {
209+
hostname = normalizeHostname(hostname);
195210
CoapClient.dtlsParams.set(hostname, params);
196211
}
197212

@@ -1041,8 +1056,9 @@ export class CoapClient {
10411056
/**
10421057
* Establishes a new or retrieves an existing connection to the given origin
10431058
* @param origin - The other party
1059+
* @internal
10441060
*/
1045-
private static getConnection(origin: Origin): Promise<ConnectionInfo> {
1061+
public static getConnection(origin: Origin): Promise<ConnectionInfo> {
10461062
const originString = origin.toString();
10471063
if (CoapClient.connections.has(originString)) {
10481064
debug(`getConnection(${originString}) => found existing connection`);
@@ -1127,8 +1143,6 @@ export class CoapClient {
11271143
// simply return a normal udp socket
11281144
return Promise.resolve(new SocketWrapper(dgram.createSocket("udp4")));
11291145
case "coaps:":
1130-
// return a promise we resolve as soon as the connection is secured
1131-
const ret = createDeferredPromise<SocketWrapper>();
11321146
// try to find security parameters
11331147
if (!CoapClient.dtlsParams.has(origin.hostname)) {
11341148
return Promise.reject(new Error(`No security parameters given for the resource at ${origin.toString()}`));
@@ -1141,6 +1155,10 @@ export class CoapClient {
11411155
} as dtls.Options),
11421156
CoapClient.dtlsParams.get(origin.hostname),
11431157
);
1158+
1159+
// return a promise we resolve as soon as the connection is secured
1160+
const ret = createDeferredPromise<SocketWrapper>();
1161+
11441162
// try connecting
11451163
const onConnection = () => {
11461164
debug("successfully created socket for origin " + origin.toString());

0 commit comments

Comments
 (0)