@seriousme/opifex 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/README.md +72 -4
- package/bin/conformanceServer.ts +1 -1
- package/bin/mqtt.ts +5 -2
- package/client/client.ts +3 -3
- package/client/context.ts +2 -0
- package/client/mod.ts +1 -2
- package/deno/client.ts +4 -3
- package/deno/server.ts +3 -2
- package/deno.json +4 -2
- package/deno.lock +0 -16
- package/dev_utils/dummyConn.ts +4 -4
- package/dist/bin/conformanceServer.js +52 -0
- package/dist/bin/demoServer.js +29 -57
- package/dist/bin/mqtt.js +148 -187
- package/dist/client/ConnectionState.js +7 -0
- package/dist/client/client.js +125 -0
- package/dist/client/context.js +148 -0
- package/dist/client/deps.js +5 -0
- package/dist/client/handlers/handleConnack.js +18 -0
- package/dist/client/handlers/handlePacket.js +50 -0
- package/dist/client/handlers/handlePuback.js +6 -0
- package/dist/client/handlers/handlePubcomp.js +9 -0
- package/dist/client/handlers/handlePublish.js +28 -0
- package/dist/client/handlers/handlePubrec.js +17 -0
- package/dist/client/handlers/handlePubrel.js +19 -0
- package/dist/client/handlers/handleSuback.js +9 -0
- package/dist/client/handlers/handleUnsuback.js +7 -0
- package/dist/client/mod.js +5 -3
- package/dist/client/store/deps.js +1 -0
- package/dist/client/store/memoryStore.js +36 -0
- package/dist/client/store/store.js +1 -0
- package/dist/mqttConn/mqttConn.js +104 -0
- package/dist/mqttPacket/AuthenticationResult.js +12 -0
- package/dist/mqttPacket/BitMask.js +10 -0
- package/dist/mqttPacket/PacketType.js +18 -0
- package/dist/mqttPacket/connack.js +27 -0
- package/dist/mqttPacket/connect.js +115 -0
- package/dist/mqttPacket/decoder.js +89 -0
- package/dist/mqttPacket/disconnect.js +14 -0
- package/dist/mqttPacket/encoder.js +56 -0
- package/dist/mqttPacket/length.js +43 -0
- package/dist/mqttPacket/mod.js +71 -0
- package/dist/mqttPacket/pingreq.js +15 -0
- package/dist/mqttPacket/pingres.js +14 -0
- package/dist/mqttPacket/puback.js +20 -0
- package/dist/mqttPacket/pubcomp.js +20 -0
- package/dist/mqttPacket/publish.js +51 -0
- package/dist/mqttPacket/pubrec.js +20 -0
- package/dist/mqttPacket/pubrel.js +20 -0
- package/dist/mqttPacket/suback.js +29 -0
- package/dist/mqttPacket/subscribe.js +52 -0
- package/dist/mqttPacket/types.js +1 -0
- package/dist/mqttPacket/unsuback.js +20 -0
- package/dist/mqttPacket/unsubscribe.js +36 -0
- package/dist/mqttPacket/validators.js +15 -0
- package/dist/node/client.js +65 -0
- package/dist/node/server.js +22 -0
- package/dist/node/wrapNodeSocket.js +47 -0
- package/dist/persistence/deps.js +3 -0
- package/dist/persistence/memory/memoryPersistence.js +117 -0
- package/dist/persistence/persistence.js +1 -0
- package/dist/persistence/store.js +1 -0
- package/dist/server/context.js +100 -0
- package/dist/server/deps.js +5 -0
- package/dist/server/handlers/handleConnect.js +46 -0
- package/dist/server/handlers/handleDisconnect.js +4 -0
- package/dist/server/handlers/handlePacket.js +58 -0
- package/dist/server/handlers/handlePingreq.js +6 -0
- package/dist/server/handlers/handlePuback.js +8 -0
- package/dist/server/handlers/handlePubcomp.js +8 -0
- package/dist/server/handlers/handlePublish.js +40 -0
- package/dist/server/handlers/handlePubrec.js +15 -0
- package/dist/server/handlers/handlePubrel.js +18 -0
- package/dist/server/handlers/handleSubscribe.js +33 -0
- package/dist/server/handlers/handleUnsubscribe.js +12 -0
- package/dist/server/mod.js +7 -589
- package/dist/server/server.js +47 -0
- package/dist/socket/socket.js +36 -0
- package/dist/timer/timer.js +40 -0
- package/dist/trie/trie.js +95 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/utils/args.js +61 -0
- package/dist/utils/assert.js +19 -0
- package/dist/utils/asyncQueue.js +56 -0
- package/dist/utils/deferred.js +11 -0
- package/dist/utils/logger.js +29 -0
- package/dist/utils/mod.js +7 -0
- package/dist/utils/nextTick.js +3 -0
- package/dist/utils/platform.js +4 -0
- package/mqttConn/mqttConn.ts +4 -1
- package/node/README.md +3 -1
- package/node/client.ts +30 -6
- package/node/server.ts +2 -0
- package/node/wrapNodeSocket.ts +4 -4
- package/package.json +16 -3
- package/server/mod.ts +1 -2
- package/socket/socket.ts +3 -2
- package/timer/timer.ts +1 -1
- package/tsconfig.json +3 -0
- package/.vscode/extensions.json +0 -10
- package/.vscode/settings.json +0 -12
- package/deno/wrapDenoConn.ts +0 -12
- package/dist/client-DqLTBVC2.js +0 -541
- package/dist/timer-DDWVNsyG.js +0 -924
- package/dist/wrapNodeSocket-BAJm059T.js +0 -115
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [Unreleased]
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
## [v1.3.0] 19-11-2024
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- update: added architectural description of Opifex to documentation
|
|
12
|
+
- update: added comments to platform specific code to explain boundary between
|
|
13
|
+
platform agnostic and platform specific.
|
|
14
|
+
- update: set default clientId in client
|
|
15
|
+
- fix: improve handling of errors if client connect fails
|
|
16
|
+
|
|
17
|
+
## [v1.2.1] 01-11-2024
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- fix: unlock last BYOB request using respond(0)
|
|
22
|
+
|
|
23
|
+
## [v1.2.0] 01-11-2024
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- added support for NodeJS < 22.0.6 by adding transpiled Javascript in `/dist`
|
|
28
|
+
|
|
29
|
+
## [v1.1.0] 01-11-2024
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
|
|
33
|
+
- added support for NodeJS >= 22.0.6 using --experimental-strip-types
|
|
34
|
+
|
|
35
|
+
## [v1.0.0] 09-10-2022
|
|
36
|
+
|
|
37
|
+
Initial version
|
package/README.md
CHANGED
|
@@ -10,14 +10,82 @@ party dependencies, it only relies on built in modules.
|
|
|
10
10
|
Its a work in progress, only does MQTT 3.1.1 and currently only has memory based
|
|
11
11
|
persistence.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
## Example
|
|
14
|
+
|
|
15
|
+
A simple server example using Deno, for more elaborate examples see the Usage
|
|
16
|
+
section below.
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { MqttServer } from "./server/mod.ts";
|
|
20
|
+
|
|
21
|
+
const listener = Deno.listen();
|
|
22
|
+
const mqttServer = new MqttServer(mqttOptions);
|
|
23
|
+
for await (const conn of this.listener) {
|
|
24
|
+
mqttServer.serve(conn);
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Architecture
|
|
29
|
+
|
|
30
|
+
1. The basis of Opifex is the MQTT packet module
|
|
31
|
+
([mqttPacket/mod.ts](mqttPacket/mod.ts)) which contains al the logic to
|
|
32
|
+
encode and decode packets.
|
|
33
|
+
|
|
34
|
+
2. On top of mqttPacket sits the MQTT connection module
|
|
35
|
+
([mqttConn/mod.ts](mqttConn/mod.ts)) module that reads packets from a
|
|
36
|
+
Readable stream and writes them to Writable stream. It will take care of
|
|
37
|
+
incomplete and/or malformed packets. mqttConn provides an async iterable that
|
|
38
|
+
can be awaited for new packets.
|
|
39
|
+
|
|
40
|
+
3. On top of mqttConn live the MQTT server ([server/mod.ts](server/mod.ts)) and
|
|
41
|
+
MQTT client ([client/mod.ts](client/mod.ts)) that take care of the MQTT
|
|
42
|
+
protocol handling like requiring an authentication to be successfull before
|
|
43
|
+
another type of packet will be accepted. Both follow a similar model of
|
|
44
|
+
implementation where for each packet that is received a handler is invoked
|
|
45
|
+
which then triggers the next step. Server and client are totally independ of
|
|
46
|
+
the technical implementation of the connection and only need a socketConn
|
|
47
|
+
([socket](socket)) to be able to work.
|
|
48
|
+
|
|
49
|
+
4. As the server needs to be able to serve multiple clients at the same time, it
|
|
50
|
+
maintains a context ([server/context.ts](server/context.ts)) per client to
|
|
51
|
+
keep track of its state and associated timers.
|
|
52
|
+
|
|
53
|
+
5. Persistence of data is handled by a pluggable persistence module
|
|
54
|
+
([persistence](persistence)) which currently only offers memory persistence
|
|
55
|
+
([persistence/memory](persistence/memory)) but can be extended with database
|
|
56
|
+
backed persistence supported by third party modules.
|
|
57
|
+
|
|
58
|
+
6. The demo server listens to a platform specific socket and runs the `serve()`
|
|
59
|
+
method from the server module on the platform independent streams of every
|
|
60
|
+
connection.
|
|
61
|
+
|
|
62
|
+
7. The demo client opens a platform specific socket and passes the resulting
|
|
63
|
+
platform independent streams to the client module.
|
|
64
|
+
|
|
65
|
+
## Usage
|
|
66
|
+
|
|
67
|
+
The most easy way to use this project is to just use the demo server
|
|
68
|
+
(demoServer) and/or the demo client (mqtt). There are separate usage
|
|
69
|
+
instructions for:
|
|
14
70
|
|
|
15
71
|
- [Deno](deno/README.md)
|
|
16
72
|
- [NodeJS](node/README.md)
|
|
17
73
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
74
|
+
If you want to change the behaviour of the server and/or the client beyond what
|
|
75
|
+
can be done with CLI options then the next step is to clone the demo server
|
|
76
|
+
and/or the client scripts and modify them to your liking.
|
|
77
|
+
|
|
78
|
+
If you want to port the platform independent client and server libs to other
|
|
79
|
+
types of transport (e.g. Unix sockets or websocketstream) then its recommended
|
|
80
|
+
to clone and modify the platform specific code in `/node` or `/deno` as well.
|
|
81
|
+
|
|
82
|
+
If you want to port the platform independent client and server libs to another
|
|
83
|
+
platform (e.g. Bun) then the platform specific code in `/node` or `/deno` might
|
|
84
|
+
serve as inspiration.
|
|
85
|
+
|
|
86
|
+
The platform independent client and server libs should also work on Bun as they
|
|
87
|
+
are engine independent, but the demo server and client currently do not work on
|
|
88
|
+
Bun because of some socket incompatibilities between Bun and the rest.
|
|
21
89
|
|
|
22
90
|
## Naming
|
|
23
91
|
|
package/bin/conformanceServer.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { AuthenticationResult } from "../server/mod.ts";
|
|
|
5
5
|
import type { Context, TAuthenticationResult, Topic } from "../server/mod.ts";
|
|
6
6
|
import { logger, LogLevel } from "../utils/mod.ts";
|
|
7
7
|
import { getArgs, parseArgs } from "../utils/mod.ts";
|
|
8
|
-
import { TcpServer } from "../
|
|
8
|
+
import { TcpServer } from "../node/server.ts";
|
|
9
9
|
|
|
10
10
|
const utf8Decoder = new TextDecoder();
|
|
11
11
|
const userTable = new Map();
|
package/bin/mqtt.ts
CHANGED
|
@@ -40,6 +40,7 @@ const connectOpts = {
|
|
|
40
40
|
boolean: ["noClean", "help"],
|
|
41
41
|
default: {
|
|
42
42
|
noClean: false,
|
|
43
|
+
clientId: `Opifex-${crypto.randomUUID()}`,
|
|
43
44
|
},
|
|
44
45
|
};
|
|
45
46
|
|
|
@@ -120,7 +121,8 @@ async function subscribe() {
|
|
|
120
121
|
}
|
|
121
122
|
} catch (err) {
|
|
122
123
|
if (err instanceof Error) {
|
|
123
|
-
|
|
124
|
+
// @ts-ignore the type spec of err is missing err.code
|
|
125
|
+
logger.info(`Error: ${err.message || err.code}`);
|
|
124
126
|
}
|
|
125
127
|
}
|
|
126
128
|
}
|
|
@@ -188,7 +190,8 @@ async function publish() {
|
|
|
188
190
|
logger.debug("Disconnected !");
|
|
189
191
|
} catch (err) {
|
|
190
192
|
if (err instanceof Error) {
|
|
191
|
-
|
|
193
|
+
// @ts-ignore the type spec of err is missing err.code
|
|
194
|
+
logger.info(`Error: ${err.message || err.code}`);
|
|
192
195
|
}
|
|
193
196
|
}
|
|
194
197
|
}
|
package/client/client.ts
CHANGED
|
@@ -96,7 +96,7 @@ export class Client {
|
|
|
96
96
|
}
|
|
97
97
|
let isReconnect = false;
|
|
98
98
|
let attempt = 1;
|
|
99
|
-
let lastMessage =
|
|
99
|
+
let lastMessage = new Error();
|
|
100
100
|
let tryConnect = true;
|
|
101
101
|
while (tryConnect) {
|
|
102
102
|
logger.debug(`${isReconnect ? "re" : ""}connecting`);
|
|
@@ -117,7 +117,7 @@ export class Client {
|
|
|
117
117
|
this.ctx.close();
|
|
118
118
|
} catch (err) {
|
|
119
119
|
if (err instanceof Error) {
|
|
120
|
-
lastMessage =
|
|
120
|
+
lastMessage = err;
|
|
121
121
|
}
|
|
122
122
|
logger.debug(lastMessage);
|
|
123
123
|
if (!isReconnect && attempt > this.numberOfRetries) {
|
|
@@ -129,7 +129,7 @@ export class Client {
|
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
if (isReconnect === false) {
|
|
132
|
-
this.ctx.unresolvedConnect?.reject(
|
|
132
|
+
this.ctx.unresolvedConnect?.reject(lastMessage);
|
|
133
133
|
}
|
|
134
134
|
}
|
|
135
135
|
|
package/client/context.ts
CHANGED
|
@@ -91,8 +91,10 @@ export class Context {
|
|
|
91
91
|
if (this.mqttConn === undefined) {
|
|
92
92
|
return true;
|
|
93
93
|
}
|
|
94
|
+
logger.debug("Send connect packet");
|
|
94
95
|
await this.connect(connectPacket);
|
|
95
96
|
try {
|
|
97
|
+
logger.debug("Accepting packets");
|
|
96
98
|
for await (const packet of this.mqttConn) {
|
|
97
99
|
handlePacket(this, packet);
|
|
98
100
|
}
|
package/client/mod.ts
CHANGED
package/deno/client.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
// This a Deno specific implementation of TCP client sockets
|
|
2
|
+
// it extends the platform agnostic Client class
|
|
1
3
|
import { Client } from "../client/client.ts";
|
|
2
4
|
import { logger } from "../client/deps.ts";
|
|
3
|
-
import { wrapDenoConn } from "./wrapDenoConn.ts";
|
|
4
5
|
import type { SockConn } from "../client/deps.ts";
|
|
5
6
|
|
|
6
7
|
export async function getCaCerts(filename: string | undefined) {
|
|
@@ -17,7 +18,7 @@ export async function getCaCerts(filename: string | undefined) {
|
|
|
17
18
|
export class TcpClient extends Client {
|
|
18
19
|
protected async connectMQTT(hostname: string, port = 1883) {
|
|
19
20
|
logger.debug({ hostname, port });
|
|
20
|
-
return
|
|
21
|
+
return await Deno.connect({ hostname, port });
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
protected async connectMQTTS(
|
|
@@ -26,7 +27,7 @@ export class TcpClient extends Client {
|
|
|
26
27
|
caCerts?: string[],
|
|
27
28
|
) {
|
|
28
29
|
logger.debug({ hostname, port, caCerts });
|
|
29
|
-
return
|
|
30
|
+
return await Deno.connectTls({ hostname, port, caCerts });
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
protected override createConn(
|
package/deno/server.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
// This a Deno specific implementation of a TCP socket listener
|
|
2
|
+
// it uses the platform agnostic MqttServer class
|
|
1
3
|
import { MqttServer } from "../server/mod.ts";
|
|
2
4
|
import type { MqttServerOptions } from "../server/mod.ts";
|
|
3
|
-
import { wrapDenoConn } from "./wrapDenoConn.ts";
|
|
4
5
|
|
|
5
6
|
export class TcpServer {
|
|
6
7
|
private listener: Deno.Listener<Deno.Conn>;
|
|
@@ -15,7 +16,7 @@ export class TcpServer {
|
|
|
15
16
|
|
|
16
17
|
async start() {
|
|
17
18
|
for await (const conn of this.listener) {
|
|
18
|
-
this.mqttServer.serve(
|
|
19
|
+
this.mqttServer.serve(conn);
|
|
19
20
|
}
|
|
20
21
|
}
|
|
21
22
|
stop() {
|
package/deno.json
CHANGED
package/deno.lock
CHANGED
|
@@ -1,22 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": "4",
|
|
3
3
|
"specifiers": {
|
|
4
|
-
"jsr:@std/assert@1.0.2": "1.0.2",
|
|
5
|
-
"jsr:@std/internal@^1.0.1": "1.0.1",
|
|
6
4
|
"npm:@types/node@*": "22.5.4",
|
|
7
5
|
"npm:@types/node@^22.8.6": "22.8.6"
|
|
8
6
|
},
|
|
9
|
-
"jsr": {
|
|
10
|
-
"@std/assert@1.0.2": {
|
|
11
|
-
"integrity": "ccacec332958126deaceb5c63ff8b4eaf9f5ed0eac9feccf124110435e59e49c",
|
|
12
|
-
"dependencies": [
|
|
13
|
-
"jsr:@std/internal"
|
|
14
|
-
]
|
|
15
|
-
},
|
|
16
|
-
"@std/internal@1.0.1": {
|
|
17
|
-
"integrity": "6f8c7544d06a11dd256c8d6ba54b11ed870aac6c5aeafff499892662c57673e6"
|
|
18
|
-
}
|
|
19
|
-
},
|
|
20
7
|
"npm": {
|
|
21
8
|
"@types/node@22.5.4": {
|
|
22
9
|
"integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==",
|
|
@@ -35,9 +22,6 @@
|
|
|
35
22
|
}
|
|
36
23
|
},
|
|
37
24
|
"workspace": {
|
|
38
|
-
"dependencies": [
|
|
39
|
-
"jsr:@std/assert@1.0.2"
|
|
40
|
-
],
|
|
41
25
|
"packageJson": {
|
|
42
26
|
"dependencies": [
|
|
43
27
|
"npm:@types/node@^22.8.6"
|
package/dev_utils/dummyConn.ts
CHANGED
|
@@ -68,7 +68,7 @@ function ReadableStreamFrom(
|
|
|
68
68
|
export function makeDummySockConn(
|
|
69
69
|
readerBuffs: Uint8Array[],
|
|
70
70
|
writerBuf: Uint8Array,
|
|
71
|
-
|
|
71
|
+
close = () => {},
|
|
72
72
|
) {
|
|
73
73
|
const readBlob = new Blob(readerBuffs);
|
|
74
74
|
const readable = readBlob.stream();
|
|
@@ -76,20 +76,20 @@ export function makeDummySockConn(
|
|
|
76
76
|
return {
|
|
77
77
|
readable,
|
|
78
78
|
writable,
|
|
79
|
-
|
|
79
|
+
close,
|
|
80
80
|
};
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
export function makeDummyQueueSockConn(
|
|
84
84
|
r: AsyncQueue<Uint8Array>,
|
|
85
85
|
w: AsyncQueue<Uint8Array>,
|
|
86
|
-
|
|
86
|
+
close = () => {},
|
|
87
87
|
) {
|
|
88
88
|
const readable = ReadableStreamFrom(r);
|
|
89
89
|
const writable = new WritableStream(new Uint8QueuedWriter(w));
|
|
90
90
|
return {
|
|
91
91
|
readable,
|
|
92
92
|
writable,
|
|
93
|
-
|
|
93
|
+
close,
|
|
94
94
|
};
|
|
95
95
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env -S node --experimental-strip-types
|
|
2
|
+
// this server is intended to be used with https://github.com/eclipse/iottestware
|
|
3
|
+
import { AuthenticationResult } from "../server/mod.js";
|
|
4
|
+
import { logger, LogLevel } from "../utils/mod.js";
|
|
5
|
+
import { getArgs, parseArgs } from "../utils/mod.js";
|
|
6
|
+
import { TcpServer } from "../node/server.js";
|
|
7
|
+
const utf8Decoder = new TextDecoder();
|
|
8
|
+
const userTable = new Map();
|
|
9
|
+
userTable.set("IoTester_1", "strong_password");
|
|
10
|
+
userTable.set("IoTester_2", "strong_password");
|
|
11
|
+
const strictUsername = new RegExp(/^[a-zA-Z0-9]{0,23}$/);
|
|
12
|
+
const notAuthorizedTable = new Set();
|
|
13
|
+
notAuthorizedTable.add(["123-456-789", "eclipse/iot/tesware/0data"]);
|
|
14
|
+
function isAuthenticated(_ctx, clientId, username, password) {
|
|
15
|
+
const pwd = utf8Decoder.decode(password);
|
|
16
|
+
logger.debug(`Verifying authentication of client '${clientId}' with username '${username}' and password '${pwd}'`);
|
|
17
|
+
if (!userTable.has(username)) {
|
|
18
|
+
if (!strictUsername.test(username)) {
|
|
19
|
+
return AuthenticationResult.badUsernameOrPassword;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const pass = userTable.get(username);
|
|
23
|
+
if (pwd === pass) {
|
|
24
|
+
return AuthenticationResult.ok;
|
|
25
|
+
}
|
|
26
|
+
return AuthenticationResult.notAuthorized;
|
|
27
|
+
}
|
|
28
|
+
function isAuthorizedToPublish(ctx, topic) {
|
|
29
|
+
logger.debug(`Checking authorization of client '${ctx.store?.clientId}' to publish on topic '${topic}'`);
|
|
30
|
+
// if (notAuthorizedTable.has([ctx.client,topic])){
|
|
31
|
+
// return false;
|
|
32
|
+
// }
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
function isAuthorizedToSubscribe(ctx, topic) {
|
|
36
|
+
logger.debug(`Checking authorization of client '${ctx.store?.clientId}' to subscribe to topic '${topic}'`);
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
/** start the server **/
|
|
40
|
+
const { _: [portNum] } = parseArgs(getArgs());
|
|
41
|
+
const port = Number(portNum ?? 1883);
|
|
42
|
+
const hostname = "::";
|
|
43
|
+
logger.level(LogLevel.info);
|
|
44
|
+
const tcpServer = new TcpServer({ port, hostname }, {
|
|
45
|
+
handlers: {
|
|
46
|
+
isAuthenticated,
|
|
47
|
+
isAuthorizedToPublish,
|
|
48
|
+
isAuthorizedToSubscribe,
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
tcpServer.start();
|
|
52
|
+
logger.info(`Server started on port ${tcpServer.port}`);
|
package/dist/bin/demoServer.js
CHANGED
|
@@ -1,74 +1,46 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
L as LogLevel,
|
|
6
|
-
l as logger,
|
|
7
|
-
} from "../timer-DDWVNsyG.js";
|
|
8
|
-
import "node:process";
|
|
9
|
-
import { MqttServer } from "../server/mod.js";
|
|
10
|
-
import {
|
|
11
|
-
g as getArgs,
|
|
12
|
-
p as parseArgs,
|
|
13
|
-
w as wrapNodeSocket,
|
|
14
|
-
} from "../wrapNodeSocket-BAJm059T.js";
|
|
15
|
-
import "node:stream";
|
|
16
|
-
|
|
17
|
-
class TcpServer {
|
|
18
|
-
mqttServer;
|
|
19
|
-
server;
|
|
20
|
-
serverOptions;
|
|
21
|
-
constructor(serverOptions, mqttOptions) {
|
|
22
|
-
this.mqttServer = new MqttServer(mqttOptions);
|
|
23
|
-
this.serverOptions = serverOptions;
|
|
24
|
-
}
|
|
25
|
-
start() {
|
|
26
|
-
this.server = createServer(
|
|
27
|
-
(sock) => this.mqttServer.serve(wrapNodeSocket(sock)),
|
|
28
|
-
);
|
|
29
|
-
this.server.listen(this.serverOptions.port, this.serverOptions.hostname);
|
|
30
|
-
}
|
|
31
|
-
stop() {
|
|
32
|
-
this.server?.close();
|
|
33
|
-
}
|
|
34
|
-
get port() {
|
|
35
|
-
return this.serverOptions.port;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
1
|
+
#!/usr/bin/env -S node --experimental-strip-types
|
|
2
|
+
import { TcpServer } from "../node/server.js";
|
|
3
|
+
import { AuthenticationResult } from "../server/mod.js";
|
|
4
|
+
import { getArgs, logger, LogLevel, parseArgs } from "../utils/mod.js";
|
|
39
5
|
const utf8Decoder = new TextDecoder();
|
|
40
|
-
const userTable =
|
|
6
|
+
const userTable = new Map();
|
|
41
7
|
userTable.set("IoTester_1", "strong_password");
|
|
42
8
|
userTable.set("IoTester_2", "strong_password");
|
|
9
|
+
// const strictUsername = new RegExp(/^[a-zA-Z0-9]{0,23}$/);
|
|
43
10
|
function isAuthenticated(_ctx, clientId, username, password) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
11
|
+
const pwd = utf8Decoder.decode(password);
|
|
12
|
+
logger.info(`Verifying authentication of client '${clientId}' with username '${username}' and password '${pwd}'`);
|
|
13
|
+
return AuthenticationResult.ok;
|
|
14
|
+
// if (!userTable.has(username)) {
|
|
15
|
+
// if (!strictUsername.test(username)) {
|
|
16
|
+
// return AuthenticationResult.badUsernameOrPassword;
|
|
17
|
+
// }
|
|
18
|
+
// }
|
|
19
|
+
// const pass = userTable.get(username);
|
|
20
|
+
// if (pwd === pass) {
|
|
21
|
+
// return AuthenticationResult.ok;
|
|
22
|
+
// }
|
|
23
|
+
// return AuthenticationResult.badUsernameOrPassword;
|
|
49
24
|
}
|
|
50
25
|
function isAuthorizedToPublish(ctx, topic) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
);
|
|
54
|
-
return true;
|
|
26
|
+
logger.debug(`Checking authorization of client '${ctx.store?.clientId}' to publish on topic '${topic}'`);
|
|
27
|
+
return true;
|
|
55
28
|
}
|
|
56
29
|
function isAuthorizedToSubscribe(ctx, topic) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
);
|
|
60
|
-
return true;
|
|
30
|
+
logger.debug(`Checking authorization of client '${ctx.store?.clientId}' to subscribe to topic '${topic}'`);
|
|
31
|
+
return true;
|
|
61
32
|
}
|
|
33
|
+
/** start the server **/
|
|
62
34
|
const { _: [portNum] } = parseArgs(getArgs());
|
|
63
35
|
const port = Number(portNum ?? 1883);
|
|
64
36
|
const hostname = "::";
|
|
65
37
|
logger.level(LogLevel.info);
|
|
66
38
|
const tcpServer = new TcpServer({ port, hostname }, {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
39
|
+
handlers: {
|
|
40
|
+
isAuthenticated,
|
|
41
|
+
isAuthorizedToPublish,
|
|
42
|
+
isAuthorizedToSubscribe,
|
|
43
|
+
},
|
|
72
44
|
});
|
|
73
45
|
tcpServer.start();
|
|
74
46
|
logger.info(`Server started on port ${tcpServer.port}`);
|