Skip to content

Commit

Permalink
use @iobroker/webserver
Browse files Browse the repository at this point in the history
- closes #57
  • Loading branch information
foxriver76 committed Apr 21, 2024
1 parent 92bd864 commit 61af9c2
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 120 deletions.
6 changes: 6 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"extends": ["@foxriver76/eslint-config"],
"rules": {
"unicorn/prefer-module": 0
}
}
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ It is suggested to use [socket class](https://github.com/ioBroker/socket-client)
-->

## Changelog
### **WORK IN PROGRESS**
* (foxriver76) use `@iobroker/webserver`

### 2.5.10 (2023-12-17)
* (foxriver76) updated ws-server to increase file limit to 500 MB

Expand Down
35 changes: 3 additions & 32 deletions admin/jsonConfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -122,38 +122,9 @@
"height": 59
}
},
"_link": {
"newLine": true,
"type": "staticLink",
"href": "https://github.com/ioBroker/ioBroker.admin/blob/master/README.md#lets-encrypt-certificates",
"label": "Read about Let's Encrypt certificates",
"style": {
"fontSize": 16,
"marginBottom": 20
}
},
"leEnabled": {
"newLine": true,
"type": "checkbox",
"label": "Use Lets Encrypt certificates"
},
"leUpdate": {
"newLine": true,
"type": "checkbox",
"hidden": "!data.leEnabled",
"label": "Use this instance for automatic update"
},
"lePort": {
"newLine": true,
"sm": 11,
"lg": 4,
"type": "number",
"hidden": "!data.leEnabled || !data.leUpdate",
"label": "Port to check the domain",
"style": {
"marginTop": 15,
"maxWidth": 200
}
"_staticText": {
"type": "staticText",
"text": "ra_Use iobroker.acme adapter for letsencrypt certificates"
}
}
}
Expand Down
8 changes: 6 additions & 2 deletions io-package.json
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@
"authors": [
"bluefox <[email protected]>"
],
"license": "MIT",
"platform": "Javascript/Node.js",
"mode": "daemon",
"loglevel": "info",
Expand Down Expand Up @@ -154,7 +153,12 @@
}
},
"connectionType": "local",
"dataSource": "push"
"dataSource": "push",
"tier": 3,
"licenseInformation": {
"type": "free",
"license": "MIT"
}
},
"native": {
"port": 8084,
Expand Down
183 changes: 101 additions & 82 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@
'use strict';

const adapterName = require('./package.json').name.split('.').pop();
const utils = require('@iobroker/adapter-core'); // Get common adapter utils
const SocketWS = require('./lib/socketWS.js');
const LE = utils.commonTools.letsEncrypt;
const ws = require('@iobroker/ws-server');
const utils = require('@iobroker/adapter-core'); // Get common adapter utils
const SocketWS = require('./lib/socketWS.js');
const { WebServer } = '@iobroker/webserver';
const ws = require('@iobroker/ws-server');

let webServer = null;
let store = null;
let secret = 'Zgfr56gFe87jJOM'; // Will be generated by first start
let bruteForce = {};
let webServer = null;
let store = null;
let secret = 'Zgfr56gFe87jJOM'; // Will be generated by first start
const bruteForce = {};

let adapter;
function startAdapter(options) {
options = options || {};

Object.assign(options, {name: adapterName});
Object.assign(options, { name: adapterName });

adapter = new utils.Adapter(options);

Expand All @@ -44,12 +44,14 @@ function startAdapter(options) {
try {
adapter.setState && adapter.setState('info.connected', '', true);
adapter.setState && adapter.setState('info.connection', false, true);
adapter.log.info(`terminating http${webServer.settings.secure ? 's' : ''} server on port ${webServer.settings.port}`);
adapter.log.info(
`terminating http${webServer.settings.secure ? 's' : ''} server on port ${webServer.settings.port}`
);
webServer.io.close();
webServer.server.close();

callback();
} catch (e) {
} catch {
callback();
}
});
Expand All @@ -61,9 +63,9 @@ function startAdapter(options) {
if (!err && obj) {
if (!obj.native || !obj.native.secret) {
obj.native = obj.native || {};
require('crypto').randomBytes(24, (ex, buf) => {
require('node:crypto').randomBytes(24, (ex, buf) => {
secret = buf.toString('hex');
adapter.extendForeignObject('system.config', {native: {secret: secret}});
adapter.extendForeignObject('system.config', { native: { secret: secret } });
main();
});
} else {
Expand All @@ -80,7 +82,8 @@ function startAdapter(options) {
});

adapter.on('message', obj => {
if (!obj || obj.command !== 'im') { // if not instance message
if (!obj || obj.command !== 'im') {
// if not instance message
return;
}

Expand All @@ -94,8 +97,7 @@ function startAdapter(options) {
}
});

adapter.on('log', obj =>
webServer && webServer.io && webServer.io.sendLog(obj));
adapter.on('log', obj => webServer && webServer.io && webServer.io.sendLog(obj));

return adapter;
}
Expand All @@ -105,7 +107,7 @@ function main() {
// Load certificates
adapter.getCertificates((err, certificates, leConfig) => {
adapter.config.certificates = certificates;
adapter.config.leConfig = leConfig;
adapter.config.leConfig = leConfig;
webServer = initWebServer(adapter.config);
});
} else {
Expand All @@ -114,7 +116,12 @@ function main() {
}

function checkUser(username, password, cb) {
username = (username || '').toString().replace(adapter.FORBIDDEN_CHARS, '_').replace(/\s/g, '_').replace(/\./g, '_').toLowerCase();
username = (username || '')
.toString()
.replace(adapter.FORBIDDEN_CHARS, '_')
.replace(/\s/g, '_')
.replace(/\./g, '_')
.toLowerCase();

if (bruteForce[username] && bruteForce[username].errors > 4) {
let minutes = Date.now() - bruteForce[username].time;
Expand All @@ -124,22 +131,19 @@ function checkUser(username, password, cb) {
} else {
minutes = 0;
}
} else
if (bruteForce[username].errors < 10) {
} else if (bruteForce[username].errors < 10) {
if (Date.now() - bruteForce[username].time < 180000) {
minutes = Math.ceil((180000 - minutes) / 60000);
} else {
minutes = 0;
}
} else
if (bruteForce[username].errors < 15) {
} else if (bruteForce[username].errors < 15) {
if (Date.now() - bruteForce[username].time < 600000) {
minutes = Math.ceil((600000 - minutes) / 60000);
} else {
minutes = 0;
}
} else
if (Date.now() - bruteForce[username].time < 3600000) {
} else if (Date.now() - bruteForce[username].time < 3600000) {
minutes = Math.ceil((3600000 - minutes) / 60000);
} else {
minutes = 0;
Expand All @@ -152,7 +156,7 @@ function checkUser(username, password, cb) {

adapter.checkPassword(username, password, res => {
if (!res) {
bruteForce[username] = bruteForce[username] || {errors: 0};
bruteForce[username] = bruteForce[username] || { errors: 0 };
bruteForce[username].time = Date.now();
bruteForce[username].errors++;
} else if (bruteForce[username]) {
Expand All @@ -175,9 +179,9 @@ function checkUser(username, password, cb) {
//}
function initWebServer(settings) {
const server = {
app: null,
server: null,
io: null,
app: null,
server: null,
io: null,
settings
};

Expand All @@ -188,75 +192,90 @@ function initWebServer(settings) {
return null;
}

settings.crossDomain = true;
settings.ttl = settings.ttl || 3600;
settings.crossDomain = true;
settings.ttl = settings.ttl || 3600;
settings.forceWebSockets = settings.forceWebSockets || false;

if (settings.auth) {
const session = require('express-session');
const session = require('express-session');
const AdapterStore = utils.commonTools.session(session, settings.ttl);
// Authentication checked by server itself
store = new AdapterStore({adapter: adapter});
store = new AdapterStore({ adapter: adapter });
}

adapter.getPort(settings.port, (!settings.bind || settings.bind === '0.0.0.0') ? undefined : settings.bind || undefined, async port => {
if (parseInt(port, 10) !== settings.port && !adapter.config.findNextPort) {
adapter.log.error(`port ${settings.port} already in use`);
return adapter.terminate ? adapter.terminate(utils.EXIT_CODES.ADAPTER_REQUESTED_TERMINATION) : process.exit(utils.EXIT_CODES.ADAPTER_REQUESTED_TERMINATION);
}

settings.port = port;

try {
if (typeof LE.createServerAsync === 'function')
server.server = await LE.createServerAsync((req, res) => {
res.writeHead(501);
res.end('Not Implemented');
}, settings, adapter.config.certificates, adapter.config.leConfig, adapter.log, adapter);
else {
server.server = LE.createServer((req, res) => {
res.writeHead(501);
res.end('Not Implemented');
}, settings, adapter.config.certificates, adapter.config.leConfig, adapter.log);
adapter.getPort(
settings.port,
!settings.bind || settings.bind === '0.0.0.0' ? undefined : settings.bind || undefined,
async port => {
if (parseInt(port, 10) !== settings.port && !adapter.config.findNextPort) {
adapter.log.error(`port ${settings.port} already in use`);
return adapter.terminate
? adapter.terminate(utils.EXIT_CODES.ADAPTER_REQUESTED_TERMINATION)
: process.exit(utils.EXIT_CODES.ADAPTER_REQUESTED_TERMINATION);
}
} catch (err) {
adapter.log.error(`Cannot create webserver: ${err}`);
adapter.terminate ? adapter.terminate(utils.EXIT_CODES.ADAPTER_REQUESTED_TERMINATION) : process.exit(utils.EXIT_CODES.ADAPTER_REQUESTED_TERMINATION);
return;
}
if (!server.server) {
adapter.log.error(`Cannot create webserver`);
adapter.terminate ? adapter.terminate(utils.EXIT_CODES.ADAPTER_REQUESTED_TERMINATION) : process.exit(utils.EXIT_CODES.ADAPTER_REQUESTED_TERMINATION);
return;
}

let serverListening = false;
server.server.on('error', e => {
if (e.toString().includes('EACCES') && port <= 1024) {
adapter.log.error(`node.js process has no rights to start server on the port ${port}.\n` +
'Do you know that on linux you need special permissions for ports under 1024?\n' +
'You can call in shell following scrip to allow it for node.js: "iobroker fix"'
);
} else {
adapter.log.error(`Cannot start server on ${settings.bind || '0.0.0.0'}:${port}: ${e}`);
settings.port = port;

try {
const webserver = new WebServer({
app: server.app,
adapter,
secure: adapter.config.secure
});

server.server = await webserver.init();
} catch (err) {
adapter.log.error(`Cannot create webserver: ${err}`);
adapter.terminate
? adapter.terminate(utils.EXIT_CODES.ADAPTER_REQUESTED_TERMINATION)
: process.exit(utils.EXIT_CODES.ADAPTER_REQUESTED_TERMINATION);
return;
}
if (!serverListening) {
adapter.terminate ? adapter.terminate(utils.EXIT_CODES.ADAPTER_REQUESTED_TERMINATION) : process.exit(utils.EXIT_CODES.ADAPTER_REQUESTED_TERMINATION);
if (!server.server) {
adapter.log.error(`Cannot create webserver`);
adapter.terminate
? adapter.terminate(utils.EXIT_CODES.ADAPTER_REQUESTED_TERMINATION)
: process.exit(utils.EXIT_CODES.ADAPTER_REQUESTED_TERMINATION);
return;
}
});

// Start the web server
server.server.listen(settings.port, (!settings.bind || settings.bind === '0.0.0.0') ? undefined : settings.bind || undefined, () => {
adapter.setState('info.connection', true, true);
serverListening = true
});
let serverListening = false;
server.server.on('error', e => {
if (e.toString().includes('EACCES') && port <= 1024) {
adapter.log.error(
`node.js process has no rights to start server on the port ${port}.\n` +
'Do you know that on linux you need special permissions for ports under 1024?\n' +
'You can call in shell following scrip to allow it for node.js: "iobroker fix"'
);
} else {
adapter.log.error(`Cannot start server on ${settings.bind || '0.0.0.0'}:${port}: ${e}`);
}
if (!serverListening) {
adapter.terminate
? adapter.terminate(utils.EXIT_CODES.ADAPTER_REQUESTED_TERMINATION)
: process.exit(utils.EXIT_CODES.ADAPTER_REQUESTED_TERMINATION);
}
});

// Start the web server
server.server.listen(
settings.port,
!settings.bind || settings.bind === '0.0.0.0' ? undefined : settings.bind || undefined,
() => {
adapter.setState('info.connection', true, true);
serverListening = true;
}
);

server.io = new SocketWS(settings, adapter);
server.io.start(server.server, ws, {userKey: 'connect.sid', checkUser, store, secret});
});
server.io = new SocketWS(settings, adapter);
server.io.start(server.server, ws, { userKey: 'connect.sid', checkUser, store, secret });
}
);
} else {
adapter.log.error('port missing');
adapter.terminate ? adapter.terminate(utils.EXIT_CODES.ADAPTER_REQUESTED_TERMINATION) : process.exit(utils.EXIT_CODES.ADAPTER_REQUESTED_TERMINATION);
adapter.terminate
? adapter.terminate(utils.EXIT_CODES.ADAPTER_REQUESTED_TERMINATION)
: process.exit(utils.EXIT_CODES.ADAPTER_REQUESTED_TERMINATION);
}

return server;
Expand Down
Loading

0 comments on commit 61af9c2

Please sign in to comment.