matterbridge 3.1.4-dev-20250715-075e722 → 3.1.4-dev-20250717-d36e252

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 CHANGED
@@ -8,18 +8,23 @@ If you like this project and find it useful, please consider giving it a star on
8
8
  <img src="bmc-button.svg" alt="Buy me a coffee" width="120">
9
9
  </a>
10
10
 
11
- ## [3.1.4] - 2025-07-??
11
+ ## [3.1.4] - 2025-07-16
12
12
 
13
13
  ### Added
14
14
 
15
+ - [frontend]: Added support for p12 certificates. Add cert.p12 and cert.pass in the '.matterbridge/cert' directory. If both .p12 and cert.pem are present, only the .p12 will be used. See the README.md for more info.
16
+ - [frontend]: Added support for p12 certificates with mTLS: both the server and the client must present the correct certificate. Add the parameter '-mtls'. See the README.md for more info.
17
+ - [frontend]: Improved test units on Frontend class (total coverage 98%).
18
+
15
19
  ### Changed
16
20
 
17
21
  - [package]: Updated dependencies.
18
- - [bin]: Updated matterbridge bin.
19
22
  - [network]: Refactor network logging to improve clarity and update logging format.
20
23
 
21
24
  ### Fixed
22
25
 
26
+ - [bin]: Updated matterbridge bin.
27
+
23
28
  <a href="https://www.buymeacoffee.com/luligugithub">
24
29
  <img src="bmc-button.svg" alt="Buy me a coffee" width="80">
25
30
  </a>
package/README.md CHANGED
@@ -456,7 +456,7 @@ This will reset the internal storages. All commissioning informations will be lo
456
456
 
457
457
  ## How to enable HTTPS for the frontend
458
458
 
459
- ### Provide your own certificates
459
+ ### Provide your own standard certificate, key and ca (optional)
460
460
 
461
461
  Place your own certificates in the `.matterbridge/cert` directory:
462
462
 
@@ -466,14 +466,35 @@ Place your own certificates in the `.matterbridge/cert` directory:
466
466
 
467
467
  ![image](screenshot/Screenshot%20Certificates.png)
468
468
 
469
+ Matterbridge looks first for .p12 certificate and if it is not found it looks for cert.pem and key.pem.
470
+
471
+ ### Provide your own 'PKCS#12' certificate and the passphrase
472
+
473
+ Place your own p12 certificate (binary file) and the passphrase (text file) in the `.matterbridge/cert` directory:
474
+
475
+ - `cert.p12`
476
+ - `cert.pass`
477
+
478
+ Matterbridge looks first for .p12 certificate and if it is not found it looks for cert.pem and key.pem.
479
+
469
480
  ### Change the command line
470
481
 
471
- Add the **-ssl** parameter to the command line. If desired, you can also change the frontend port with **-frontend 443**.
482
+ Add the **-ssl** parameter to the command line.
483
+
484
+ If desired, you can also change the frontend port with **-frontend 443**.
472
485
 
473
486
  ```bash
474
487
  matterbridge -ssl -frontend 443
475
488
  ```
476
489
 
490
+ Add the **-mtls** parameter to the command line if you want Matterbridge to request the client (your browser) to authenticate itself (this is the most secure connection possible).
491
+
492
+ The browser must provide the client certificate: on Windows you need to import it in Current User → Personal → Certificates with certmgr.msc.
493
+
494
+ ```bash
495
+ matterbridge -ssl -mtls -frontend 443
496
+ ```
497
+
477
498
  ### Restart
478
499
 
479
500
  If the certificate are correctly configured, you will be able to connect with https to the frontend.
@@ -498,6 +519,8 @@ Then, from the dots menu in the frontend, download the `matterbridge.log` and `m
498
519
 
499
520
  ![image](screenshot/Screenshot%20Debug%20Download%20Logs.png)
500
521
 
522
+ Don't forget to unselect the debug mode when is no more needed. The network traffic and cpu usage is very high in debug mode.
523
+
501
524
  # Known general issues
502
525
 
503
526
  ## Session XYZ does not exist or Cannot find a session for ID XYZ
package/dist/frontend.js CHANGED
@@ -2,7 +2,7 @@ import { createServer } from 'node:http';
2
2
  import https from 'node:https';
3
3
  import os from 'node:os';
4
4
  import path from 'node:path';
5
- import { promises as fs } from 'node:fs';
5
+ import { existsSync, promises as fs } from 'node:fs';
6
6
  import EventEmitter from 'node:events';
7
7
  import express from 'express';
8
8
  import WebSocket, { WebSocketServer } from 'ws';
@@ -30,7 +30,6 @@ export class Frontend extends EventEmitter {
30
30
  matterbridge;
31
31
  log;
32
32
  port = 8283;
33
- initializeError = false;
34
33
  expressApp;
35
34
  httpServer;
36
35
  httpsServer;
@@ -53,6 +52,7 @@ export class Frontend extends EventEmitter {
53
52
  this.expressApp.use(express.static(path.join(this.matterbridge.rootDirectory, 'frontend/build')));
54
53
  if (!hasParameter('ssl')) {
55
54
  try {
55
+ this.log.debug(`Creating HTTP server...`);
56
56
  this.httpServer = createServer(this.expressApp);
57
57
  }
58
58
  catch (error) {
@@ -85,43 +85,76 @@ export class Frontend extends EventEmitter {
85
85
  this.log.error(`Port ${this.port} is already in use`);
86
86
  break;
87
87
  }
88
- this.initializeError = true;
89
88
  this.emit('server_error', error);
90
89
  return;
91
90
  });
92
91
  }
93
92
  else {
94
93
  let cert;
95
- try {
96
- cert = await fs.readFile(path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.pem'), 'utf8');
97
- this.log.info(`Loaded certificate file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.pem')}`);
98
- }
99
- catch (error) {
100
- this.log.error(`Error reading certificate file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.pem')}: ${error}`);
101
- this.emit('server_error', error);
102
- return;
103
- }
104
94
  let key;
105
- try {
106
- key = await fs.readFile(path.join(this.matterbridge.matterbridgeDirectory, 'certs/key.pem'), 'utf8');
107
- this.log.info(`Loaded key file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs/key.pem')}`);
108
- }
109
- catch (error) {
110
- this.log.error(`Error reading key file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs/key.pem')}: ${error}`);
111
- this.emit('server_error', error);
112
- return;
113
- }
114
95
  let ca;
115
- try {
116
- ca = await fs.readFile(path.join(this.matterbridge.matterbridgeDirectory, 'certs/ca.pem'), 'utf8');
117
- this.log.info(`Loaded CA certificate file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs/ca.pem')}`);
96
+ let fullChain;
97
+ let pfx;
98
+ let passphrase;
99
+ let httpsServerOptions = {};
100
+ if (existsSync(path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.p12'))) {
101
+ try {
102
+ pfx = await fs.readFile(path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.p12'));
103
+ this.log.info(`Loaded p12 certificate file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.p12')}`);
104
+ }
105
+ catch (error) {
106
+ this.log.error(`Error reading p12 certificate file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.p12')}: ${error}`);
107
+ this.emit('server_error', error);
108
+ return;
109
+ }
110
+ try {
111
+ passphrase = await fs.readFile(path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.pass'), 'utf8');
112
+ passphrase = passphrase.trim();
113
+ this.log.info(`Loaded p12 passphrase file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.pass')}`);
114
+ }
115
+ catch (error) {
116
+ this.log.error(`Error reading p12 passphrase file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.pass')}: ${error}`);
117
+ this.emit('server_error', error);
118
+ return;
119
+ }
120
+ httpsServerOptions = { pfx, passphrase };
118
121
  }
119
- catch (error) {
120
- this.log.info(`CA certificate file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs/ca.pem')} not loaded: ${error}`);
122
+ else {
123
+ try {
124
+ cert = await fs.readFile(path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.pem'), 'utf8');
125
+ this.log.info(`Loaded certificate file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.pem')}`);
126
+ }
127
+ catch (error) {
128
+ this.log.error(`Error reading certificate file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.pem')}: ${error}`);
129
+ this.emit('server_error', error);
130
+ return;
131
+ }
132
+ try {
133
+ key = await fs.readFile(path.join(this.matterbridge.matterbridgeDirectory, 'certs/key.pem'), 'utf8');
134
+ this.log.info(`Loaded key file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs/key.pem')}`);
135
+ }
136
+ catch (error) {
137
+ this.log.error(`Error reading key file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs/key.pem')}: ${error}`);
138
+ this.emit('server_error', error);
139
+ return;
140
+ }
141
+ try {
142
+ ca = await fs.readFile(path.join(this.matterbridge.matterbridgeDirectory, 'certs/ca.pem'), 'utf8');
143
+ fullChain = `${cert}\n${ca}`;
144
+ this.log.info(`Loaded CA certificate file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs/ca.pem')}`);
145
+ }
146
+ catch (error) {
147
+ this.log.info(`CA certificate file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs/ca.pem')} not loaded: ${error}`);
148
+ }
149
+ httpsServerOptions = { cert: fullChain ?? cert, key, ca };
150
+ }
151
+ if (hasParameter('mtls')) {
152
+ httpsServerOptions.requestCert = true;
153
+ httpsServerOptions.rejectUnauthorized = true;
121
154
  }
122
- const serverOptions = { cert, key, ca };
123
155
  try {
124
- this.httpsServer = https.createServer(serverOptions, this.expressApp);
156
+ this.log.debug(`Creating HTTPS server...`);
157
+ this.httpsServer = https.createServer(httpsServerOptions, this.expressApp);
125
158
  }
126
159
  catch (error) {
127
160
  this.log.error(`Failed to create HTTPS server: ${error}`);
@@ -153,15 +186,13 @@ export class Frontend extends EventEmitter {
153
186
  this.log.error(`Port ${this.port} is already in use`);
154
187
  break;
155
188
  }
156
- this.initializeError = true;
157
189
  this.emit('server_error', error);
158
190
  return;
159
191
  });
160
192
  }
161
- if (this.initializeError)
162
- return;
163
193
  const wssPort = this.port;
164
194
  const wssHost = hasParameter('ssl') ? `wss://${this.matterbridge.systemInformation.ipv4Address}:${wssPort}` : `ws://${this.matterbridge.systemInformation.ipv4Address}:${wssPort}`;
195
+ this.log.debug(`Creating WebSocketServer on host ${CYAN}${wssHost}${db}...`);
165
196
  this.webSocketServer = new WebSocketServer(hasParameter('ssl') ? { server: this.httpsServer } : { server: this.httpServer });
166
197
  this.webSocketServer.on('connection', (ws, request) => {
167
198
  const clientIp = request.socket.remoteAddress;
@@ -492,6 +523,7 @@ export class Frontend extends EventEmitter {
492
523
  }
493
524
  else {
494
525
  this.log.debug('WebSocket server closed successfully');
526
+ this.emit('websocket_server_stopped');
495
527
  }
496
528
  resolve();
497
529
  });
@@ -508,6 +540,7 @@ export class Frontend extends EventEmitter {
508
540
  }
509
541
  else {
510
542
  this.log.debug('Http server closed successfully');
543
+ this.emit('server_stopped');
511
544
  }
512
545
  resolve();
513
546
  });
@@ -525,6 +558,7 @@ export class Frontend extends EventEmitter {
525
558
  }
526
559
  else {
527
560
  this.log.debug('Https server closed successfully');
561
+ this.emit('server_stopped');
528
562
  }
529
563
  resolve();
530
564
  });
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "matterbridge",
3
- "version": "3.1.4-dev-20250715-075e722",
3
+ "version": "3.1.4-dev-20250717-d36e252",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "matterbridge",
9
- "version": "3.1.4-dev-20250715-075e722",
9
+ "version": "3.1.4-dev-20250717-d36e252",
10
10
  "license": "Apache-2.0",
11
11
  "dependencies": {
12
12
  "@matter/main": "0.15.1",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "matterbridge",
3
- "version": "3.1.4-dev-20250715-075e722",
3
+ "version": "3.1.4-dev-20250717-d36e252",
4
4
  "description": "Matterbridge plugin manager for Matter",
5
5
  "author": "https://github.com/Luligu",
6
6
  "license": "Apache-2.0",