Skip to content

Commit

Permalink
new config options for context storage, auth, projects (#31 #132 #78 #45
Browse files Browse the repository at this point in the history
)
  • Loading branch information
hobbyquaker committed Jan 10, 2019
1 parent 549ccd9 commit 6340afa
Show file tree
Hide file tree
Showing 5 changed files with 382 additions and 94 deletions.
15 changes: 14 additions & 1 deletion addon_files/redmatic/etc/default-settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,20 @@
},
"contextStorage": {
"default": {
"module": "localfilesystem"
"module": "memory"
},
"memory": {
"module": "memory"
},
"file": {
"module": "localfilesystem",
"dir": "/usr/local/addons/redmatic/var",
"flushInterval": 30
}
},
"editorTheme": {
"projects": {
"enabled": false
}
},
"restartOnCrash": 0
Expand Down
91 changes: 91 additions & 0 deletions addon_files/redmatic/lib/rega-auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
const path = require('path');
const dgram = require('dgram');

const Rega = require(path.join(__dirname, '..', 'var/node_modules/node-red-contrib-ccu/node_modules/homematic-rega'));

const regaHost = '127.0.0.1';
const regaAuthPort = 1998;
const regaScriptPort = 8183;

const rega = new Rega({
host: regaHost,
port: regaScriptPort
});

function getUserLevel(username, callback) {
rega.exec(`
var user = dom.GetObject(ID_USERS).Get("${username}");
var level;
if (user) {
level = user.UserLevel();
}
`, (err, stdout, objects) => {
if (objects.user === username) {
let permissions;
switch (objects.level) {
// Todo set Node-RED permissions dependent on Rega User Level
/*
case 8:
// Admin
break;
case 2:
// User
break;
case 1:
// Guest
break;
*/
default:
permissions = '*';
}
callback({username, permissions})
} else {
callback(null)
}
});
}

function escapeColon(str) {
return str.replace(/\\/g, '\\\\').replace(/:/g, '\\:');
}

function checkPassword(username, password, callback) {
const message = Buffer.from(escapeColon(username) + ':' + escapeColon(password));
const client = dgram.createSocket('udp4');
client.on('message', (msg, rinfo) => {
client.close();
callback(rinfo.size === 1 && msg.toString() === '1');
});
client.send(message, regaAuthPort, regaHost);
}

module.exports = {
type: "credentials",
users: username => {
return new Promise(resolve => {
getUserLevel(username, resolve);
});
},
authenticate: (username, password) => {
return new Promise(resolve => {
getUserLevel(username, user => {
if (user) {
checkPassword(username, password, valid => {
if (valid) {
resolve(user);
} else {
resolve(null);
}
});
} else {
resolve(null);
}
});
});
},
default: () => {
return new Promise(resolve => {
resolve(null);
});
}
};
22 changes: 20 additions & 2 deletions addon_files/redmatic/lib/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,32 @@ if (fs.existsSync('/usr/local/addons/redmatic/etc/credentials.key')) {
delete defaults.logging.console;
Object.assign(logging.logging.ain, settings.logging.ain);

// https://github.com/HM-RedMatic/RedMatic/issues/45
// Enable Projects Feature
if (!defaults.editorTheme) {
defaults.editorTheme = {};
}
if (!defaults.editorTheme.projects) {
defaults.editorTheme.projects = {};
}
defaults.editorTheme.projects.enabled = false;
defaults.editorTheme.projects.enabled = defaults.editorTheme.projects.enabled || false;

// Inject sessionExpiryTime to Rega Authentication
if (settings.adminAuth && settings.adminAuth.type === 'rega') {
const regaAuth = require('/usr/local/addons/redmatic/lib/rega-auth.js');
if (settings.adminAuth.sessionExpiryTime) {
regaAuth.sessionExpiryTime = settings.adminAuth.sessionExpiryTime;
}
settings.adminAuth = regaAuth;
}

// Context Storage
if (settings.contextStorage.default.module === 'localfilesystem') {
settings.contextStorage.default.module = 'sd';
}

const defaultContextStorage = Object.assign({}, settings.contextStorage[settings.contextStorage.default.module]);
delete settings.contextStorage[settings.contextStorage.default.module];
settings.contextStorage.default = defaultContextStorage;

module.exports = Object.assign(
defaults,
Expand Down
130 changes: 123 additions & 7 deletions addon_files/redmatic/www/js/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ $(document).ready(() => {
const bcrypt = dcodeIO.bcrypt;

const $loglevel = $('#loglevel');
const $contextStorage = $('#context-storage');
const $contextStorageDefault = $('#context-storage-default');
const $contextStorageFilePath = $('#context-storage-file-path');
const $contextStorageFileInterval = $('#context-storage-file-interval');

const $adminauthType = $('#adminauth-type');
const $adminauthCreds = $('#adminauth-credentials');
const $adminauthExpiry = $('#adminauth-expiry');
const $adminauthSessionExpiryTime = $('#adminauth-sessionExpiryTime');
const $adminauthUser = $('#adminauth-user');
const $adminauthPass1 = $('#adminauth-pass1');
const $adminauthPass2 = $('#adminauth-pass2');
Expand All @@ -24,6 +28,8 @@ $(document).ready(() => {
const $staticauthPass1 = $('#staticauth-pass1');
const $staticauthPass2 = $('#staticauth-pass2');
const $staticauthSet = $('#staticauth-set');

const $projects = $('#projects');

const $alertSaved = $('#alert-saved');
const $alertError = $('#alert-error');
Expand Down Expand Up @@ -144,6 +150,7 @@ $(document).ready(() => {
}

function save() {
console.log('save', config)
$.post({
url: 'setconfig.cgi' + location.search,
data: JSON.stringify(config, null, ' '),
Expand All @@ -162,12 +169,18 @@ $(document).ready(() => {
$.get('getconfig.cgi' + location.search, (data, success) => {
config = JSON.parse(data);
$loglevel.val(config.logging.ain.level);
$contextStorage.val(config.contextStorage.default.module);

if (config.adminAuth) {
$adminauthSessionExpiryTime.val(config.adminAuth.sessionExpiryTime || '604800');
$adminauthType.val(config.adminAuth.type);
$adminauthCreds.show();
$adminauthUser.val(config.adminAuth.users[0].username);
if (config.adminAuth.type === 'credentials') {
$adminauthCreds.show();
$adminauthExpiry.show();
$adminauthUser.val(config.adminAuth.users[0].username);

} else if (config.adminAuth.type === 'rega') {
$adminauthExpiry.show();
}
}

if (config.httpNodeAuth) {
Expand All @@ -182,6 +195,53 @@ $(document).ready(() => {
$staticauthUser.val(config.httpStaticAuth.user);
}

if (!config.contextStorage) {
config.contextStorage = {};
}
if (!config.contextStorage.default || !config.contextStorage.default.module) {
config.contextStorage.default = {module: 'memory'};
}
if (!config.contextStorage.memory) {
config.contextStorage.memory = {
'module': 'memory'
};
}
if (!config.contextStorage.file) {
config.contextStorage.file = {
'module': 'localfilesystem',
dir: '/usr/local/addons/redmatic/var',
flushInterval: 30
};
}

if (!config.editorTheme) {
config.editorTheme = {};
}
if (!config.editorTheme.projects) {
config.editorTheme.projects = {};
}
config.editorTheme.projects.enabled = config.editorTheme.projects.enabled || false;

$projects.val(String(config.editorTheme.projects.enabled));

if (config.editorTheme.projects.enabled) {
$projects.prop('disabled', true);
}

// Migration from 1.x to 2.x
if (config.contextStorage.default && config.contextStorage.default.module === 'localfilesystem') {
config.contextStorage.default.module = 'file';
}

config.contextStorage.default.module = config.contextStorage.default.module || 'memory';

updateContextTitle();

$contextStorageDefault.val(config.contextStorage.default.module);

$contextStorageFilePath.val(config.contextStorage.file.dir);
$contextStorageFileInterval.val(config.contextStorage.file.flushInterval);

$('#autorestart').find('option[value="' + config.restartOnCrash + '"]').attr('selected', true);

});
Expand All @@ -191,21 +251,74 @@ $(document).ready(() => {
save();
});

$contextStorage.change(() => {
function updateContextTitle() {
switch (config.contextStorage.default.module) {
case 'memory':
$('#context-file-title').html('file');
$('#context-memory-title').html('default');
break;
case 'file':
$('#context-file-title').html('default');
$('#context-memory-title').html('memory');
break;
default:
}
}

$projects.change(() => {
config.editorTheme.projects.enabled = $projects.val() === 'true';
save();
if (config.editorTheme.projects.enabled) {
$projects.prop('disabled', true)
}
});

$contextStorageDefault.change(() => {
if (!config.contextStorage) {
config.contextStorage = {default: {}};
config.contextStorage = {};
}
if (!config.contextStorage.default) {
config.contextStorage.default = {};
}
config.contextStorage.default.module = $contextStorage.val();

config.contextStorage.default.module = $contextStorageDefault.val();
updateContextTitle();

save();
});

$adminauthSessionExpiryTime.change(() => {
if (!config.adminAuth) {
config.adminAuth = {};
}
const time = parseInt($adminauthSessionExpiryTime.val(), 10) || 604800;
if (config.adminAuth.sessionExpiryTime !== time) {
config.adminAuth.sessionExpiryTime = time;
save();
}
});

$adminauthType.change(() => {
switch ($adminauthType.val()) {
case 'credentials':
$adminauthCreds.show();
break;
case 'rega':
$adminauthExpiry.show();
$adminauthCreds.hide();
$adminauthUser.val('');
if (!config.adminAuth) {
config.adminAuth = {};
}
delete config.adminAuth.users;
config.adminAuth.type = 'rega';
config.adminAuth.sessionExpiryTime = parseInt($adminauthSessionExpiryTime.val(), 10) || 604800;
save();
break;
default:
$adminauthExpiry.hide();
$adminauthCreds.hide();
$adminauthUser.val('');
delete config.adminAuth;
save();
}
Expand All @@ -218,6 +331,7 @@ $(document).ready(() => {
break;
default:
$nodeauthCreds.hide();
$nodeauthUser.val('');
delete config.httpNodeAuth;
save();
}
Expand All @@ -230,6 +344,7 @@ $(document).ready(() => {
break;
default:
$staticauthCreds.hide();
$staticauthUser.val('');
delete config.httpStaticAuth;
save();
}
Expand Down Expand Up @@ -262,6 +377,7 @@ $(document).ready(() => {
config = Object.assign(config, {
adminAuth: {
type: 'credentials',
sessionExpiryTime: parseInt($adminauthSessionExpiryTime.val(), 10) || 604800,
users: [{
username: user,
password: bcrypt.hashSync(pw1, 8),
Expand Down
Loading

0 comments on commit 6340afa

Please sign in to comment.