From 5d29fa5e626c7f990d84fa81c556d824f8761d41 Mon Sep 17 00:00:00 2001 From: Joseph Bethge Date: Thu, 29 Sep 2016 16:34:57 +0200 Subject: [PATCH 1/8] ip address filtering --- CHANGELOG.md | 1 + config/config.js.sample | 3 +++ js/server.js | 6 ++++++ package.json | 1 + 4 files changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 326bfc49..74cb3f7e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Added - Method to overwrite the module's header. [See documentation.](https://github.com/MichMich/MagicMirror/tree/develop/modules#getheader) +- Option to limit access to certain IP addresses based on the value of `ipWhitelist` in the `config.js`, default is access from localhost only (Issue [#456](https://github.com/MichMich/MagicMirror/issues/456)) ### Updated - Modified translations for Frysk. diff --git a/config/config.js.sample b/config/config.js.sample index 04c7fba9..b10c9915 100644 --- a/config/config.js.sample +++ b/config/config.js.sample @@ -6,6 +6,9 @@ var config = { port: 8080, + ipWhitelist: ['127.0.0.1', '::ffff:127.0.0.1'], + // you use ips with subnet mask: ['127.0.0.1', '127.0.0.1/24'] + // you use also use ip ranges: ['127.0.0.1', ['192.168.0.1', '192.168.0.100']] language: 'en', timeFormat: 24, diff --git a/js/server.js b/js/server.js index 2ab0b1b9..b8dcec59 100644 --- a/js/server.js +++ b/js/server.js @@ -10,11 +10,17 @@ var app = require("express")(); var server = require("http").Server(app); var io = require("socket.io")(server); var path = require("path"); +var ipfilter = require('express-ipfilter').IpFilter; var Server = function(config, callback) { console.log("Starting server op port " + config.port + " ... "); server.listen(config.port); + if (config.ipWhitelist === undefined) { + config.ipWhitelist = ['127.0.0.1', '::ffff:127.0.0.1']; + console.log("Warning: Missing value (ipWhitelist) from config.js, assuming default (localhost access only): " + config.ipWhitelist); + } + app.use(ipfilter(config.ipWhitelist, {mode: 'allow', log: false})); app.use("/js", express.static(__dirname)); app.use("/config", express.static(path.resolve(__dirname + "/../config"))); app.use("/css", express.static(path.resolve(__dirname + "/../css"))); diff --git a/package.json b/package.json index afdad5f6..cfef5f85 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "dependencies": { "electron-prebuilt": "^0.37.2", "express": "^4.14.0", + "express-ipfilter": "latest", "feedme": "latest", "iconv-lite": "latest", "moment": "latest", From f378c93dd3e7a558d6835fd9f4a29e6e42405e8a Mon Sep 17 00:00:00 2001 From: Joseph Bethge Date: Thu, 29 Sep 2016 17:07:22 +0200 Subject: [PATCH 2/8] replace ugly error message --- js/server.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/js/server.js b/js/server.js index b8dcec59..ddcf1dd3 100644 --- a/js/server.js +++ b/js/server.js @@ -20,7 +20,16 @@ var Server = function(config, callback) { config.ipWhitelist = ['127.0.0.1', '::ffff:127.0.0.1']; console.log("Warning: Missing value (ipWhitelist) from config.js, assuming default (localhost access only): " + config.ipWhitelist); } - app.use(ipfilter(config.ipWhitelist, {mode: 'allow', log: false})); + + app.use(function(req, res, next) { + var result = ipfilter(config.ipWhitelist, {mode: 'allow', log: false})(req, res, function(err) { + if (err === undefined) { + return next(); + } + res.status(403).send("This device is not allowed to access your mirror.
Please check your config.js or config.js.sample to change this."); + }); + }); + app.use("/js", express.static(__dirname)); app.use("/config", express.static(path.resolve(__dirname + "/../config"))); app.use("/css", express.static(path.resolve(__dirname + "/../css"))); From b58314007794d92e7e33dcc5e30a82cd9f2b6ab8 Mon Sep 17 00:00:00 2001 From: Joseph Bethge Date: Thu, 29 Sep 2016 17:26:32 +0200 Subject: [PATCH 3/8] fix double quotes and config.js.sample --- config/config.js.sample | 4 ++-- js/defaults.js | 1 + js/server.js | 6 +++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/config/config.js.sample b/config/config.js.sample index b10c9915..933b62fd 100644 --- a/config/config.js.sample +++ b/config/config.js.sample @@ -7,8 +7,8 @@ var config = { port: 8080, ipWhitelist: ['127.0.0.1', '::ffff:127.0.0.1'], - // you use ips with subnet mask: ['127.0.0.1', '127.0.0.1/24'] - // you use also use ip ranges: ['127.0.0.1', ['192.168.0.1', '192.168.0.100']] + // you can use ips with subnet mask: ['127.0.0.1', '127.0.0.1/24'] + // you can also use ip ranges: ['127.0.0.1', ['192.168.0.1', '192.168.0.100']] language: 'en', timeFormat: 24, diff --git a/js/defaults.js b/js/defaults.js index 0688595c..d1d78bce 100644 --- a/js/defaults.js +++ b/js/defaults.js @@ -10,6 +10,7 @@ var defaults = { port: 8080, kioskmode: false, + ipWhitelist: ['127.0.0.1', '::ffff:127.0.0.1'], language: "en", timeFormat: 24, diff --git a/js/server.js b/js/server.js index ddcf1dd3..edae0e12 100644 --- a/js/server.js +++ b/js/server.js @@ -10,19 +10,19 @@ var app = require("express")(); var server = require("http").Server(app); var io = require("socket.io")(server); var path = require("path"); -var ipfilter = require('express-ipfilter').IpFilter; +var ipfilter = require("express-ipfilter").IpFilter; var Server = function(config, callback) { console.log("Starting server op port " + config.port + " ... "); server.listen(config.port); if (config.ipWhitelist === undefined) { - config.ipWhitelist = ['127.0.0.1', '::ffff:127.0.0.1']; + config.ipWhitelist = ["127.0.0.1", "::ffff:127.0.0.1"]; console.log("Warning: Missing value (ipWhitelist) from config.js, assuming default (localhost access only): " + config.ipWhitelist); } app.use(function(req, res, next) { - var result = ipfilter(config.ipWhitelist, {mode: 'allow', log: false})(req, res, function(err) { + var result = ipfilter(config.ipWhitelist, {mode: "allow", log: false})(req, res, function(err) { if (err === undefined) { return next(); } From 66eb99e5068cd69d394946d0c635e4d8012f0b13 Mon Sep 17 00:00:00 2001 From: Joseph Bethge Date: Thu, 29 Sep 2016 17:49:54 +0200 Subject: [PATCH 4/8] transfer usage information to readme --- README.md | 2 ++ config/config.js.sample | 4 +--- js/defaults.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d86cca7c..986e600b 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,8 @@ The following properties can be configured: | **Option** | **Description** | | --- | --- | | `port` | The port on which the MagicMirror² server will run on. The default value is `8080`. | +| `ipWhitelist` | The list of IPs from which you are allowed to access the MagicMirror². The default value is `["127.0.0.1", "::ffff:127.0.0.1"]`.It is possible to specify IPs with subnet masks (`["127.0.0.1", "127.0.0.1/24"]`) or define ip ranges (`["127.0.0.1", ["192.168.0.1", "192.168.0.100"]]`). + | | `kioskmode` | This allows MagicMirror² to run in Kiosk Mode. It protects from other programs popping on top of your screen. The default value is `false`| | `language` | The language of the interface. (Note: Not all elements will be localized.) Possible values are `en`, `nl`, `ru`, `fr`, etc., but the default value is `en`. | | `timeFormat` | The form of time notation that will be used. Possible values are `12` or `24`. The default is `24`. | diff --git a/config/config.js.sample b/config/config.js.sample index 933b62fd..269492ba 100644 --- a/config/config.js.sample +++ b/config/config.js.sample @@ -6,9 +6,7 @@ var config = { port: 8080, - ipWhitelist: ['127.0.0.1', '::ffff:127.0.0.1'], - // you can use ips with subnet mask: ['127.0.0.1', '127.0.0.1/24'] - // you can also use ip ranges: ['127.0.0.1', ['192.168.0.1', '192.168.0.100']] + ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1"], language: 'en', timeFormat: 24, diff --git a/js/defaults.js b/js/defaults.js index d1d78bce..e2ee6151 100644 --- a/js/defaults.js +++ b/js/defaults.js @@ -10,7 +10,7 @@ var defaults = { port: 8080, kioskmode: false, - ipWhitelist: ['127.0.0.1', '::ffff:127.0.0.1'], + ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1"], language: "en", timeFormat: 24, From 2c758a9981a8b586639b6218c8c44f5e984fcfae Mon Sep 17 00:00:00 2001 From: Joseph Bethge Date: Thu, 29 Sep 2016 17:52:22 +0200 Subject: [PATCH 5/8] remove warning message --- js/server.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/js/server.js b/js/server.js index edae0e12..cd3d77f2 100644 --- a/js/server.js +++ b/js/server.js @@ -16,10 +16,6 @@ var Server = function(config, callback) { console.log("Starting server op port " + config.port + " ... "); server.listen(config.port); - if (config.ipWhitelist === undefined) { - config.ipWhitelist = ["127.0.0.1", "::ffff:127.0.0.1"]; - console.log("Warning: Missing value (ipWhitelist) from config.js, assuming default (localhost access only): " + config.ipWhitelist); - } app.use(function(req, res, next) { var result = ipfilter(config.ipWhitelist, {mode: "allow", log: false})(req, res, function(err) { From 5899497aa73bbbf1deb3297f8fe29b7c044b4671 Mon Sep 17 00:00:00 2001 From: Joseph Bethge Date: Thu, 29 Sep 2016 17:55:32 +0200 Subject: [PATCH 6/8] log denied access attempts on server --- js/server.js | 1 + 1 file changed, 1 insertion(+) diff --git a/js/server.js b/js/server.js index cd3d77f2..e1a90946 100644 --- a/js/server.js +++ b/js/server.js @@ -22,6 +22,7 @@ var Server = function(config, callback) { if (err === undefined) { return next(); } + console.log(err.message); res.status(403).send("This device is not allowed to access your mirror.
Please check your config.js or config.js.sample to change this."); }); }); From c4048f4c7b6155c01681456f33002a1a279f2a41 Mon Sep 17 00:00:00 2001 From: Doug McInnes Date: Fri, 23 Sep 2016 21:48:49 -0700 Subject: [PATCH 7/8] fix typos in the module dev docs --- modules/README.md | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/modules/README.md b/modules/README.md index 61989a93..e7a23abd 100644 --- a/modules/README.md +++ b/modules/README.md @@ -6,11 +6,11 @@ This document describes the way to develop your own MagicMirror² modules. All modules are loaded in the `modules` folder. The default modules are grouped together in the `modules/default` folder. Your module should be placed in a subfolder of `modules`. Note that any file or folder your create in the `modules` folder will be ignored by git, allowing you to upgrade the MagicMirror² without the loss of your files. -A module can be placed in one single folder. Or multiple modules can be grouped in a subfoler. Note that name of the module must be unique. Even when a module with a similar name is placed in a different folder, they can't be loaded at the same time. +A module can be placed in one single folder. Or multiple modules can be grouped in a subfolder. Note that name of the module must be unique. Even when a module with a similar name is placed in a different folder, they can't be loaded at the same time. ### Files - **modulename/modulename.js** - This is your core module script. -- **modulename/node_helper.js** - This is an optional helper that whill be loaded by the node script. The node helper and module script can communicate with each other using an intergrated socket system. +- **modulename/node_helper.js** - This is an optional helper that will be loaded by the node script. The node helper and module script can communicate with each other using an intergrated socket system. - **modulename/public** - Any files in this folder can be accesed via the browser on `/modulename/filename.ext`. - **modulename/anyfileorfolder** Any other file or folder in the module folder can be used by the core module script. For example: *modulename/css/modulename.css* would be a good path for your additional module styles. @@ -104,7 +104,7 @@ The getScripts method is called to request any additional scripts that need to b getScripts: function() { return [ 'script.js', // will try to load it from the vendor folder, otherwise it will load is from the module folder. - 'moment.js', // this file is available in the vendor folder, so it doesn't need to be avialable in the module folder. + 'moment.js', // this file is available in the vendor folder, so it doesn't need to be available in the module folder. this.file('anotherfile.js'), // this file will be loaded straight from the module folder. 'https://code.jquery.com/jquery-2.2.3.min.js', // this file will be loaded from the jquery servers. ] @@ -154,7 +154,7 @@ getTranslations: function() { ####`getDom()` **Should return:** Dom Object -Whenever the MagicMirror needs to update the information on screen (because it starts, or because your module asked a refresh using `this.updateDom()`), the system calls the getDom method. This method should therefor return a dom object. +Whenever the MagicMirror needs to update the information on screen (because it starts, or because your module asked a refresh using `this.updateDom()`), the system calls the getDom method. This method should therefore return a dom object. **Example:** ````javascript @@ -202,7 +202,7 @@ notificationReceived: function(notification, payload, sender) { } ```` -**Note:** the system sends two notifiations when starting up. These notifications could come in handy! +**Note:** the system sends two notifications when starting up. These notifications could come in handy! - `ALL_MODULES_STARTED` - All modules are started. You can now send notifications to other modules. @@ -215,8 +215,8 @@ When using a node_helper, the node helper can send your module notifications. Wh - `notification` - String - The notification identifier. - `payload` - AnyType - The payload of a notification. -**Note 1:** When a node helper send a notification, all modules of that module type receive the same notifications.
-**Note 2:** The socket connection is established as soon as the module sends it's first message using [sendSocketNotification](thissendsocketnotificationnotification-payload). +**Note 1:** When a node helper sends a notification, all modules of that module type receive the same notifications.
+**Note 2:** The socket connection is established as soon as the module sends its first message using [sendSocketNotification](thissendsocketnotificationnotification-payload). **Example:** ````javascript @@ -234,7 +234,7 @@ When a module will be shown after it was previously hidden (using the `module.sh ### Module instance methods -Each module instance has some handy methods which can be helpfull building your module. +Each module instance has some handy methods which can be helpful building your module. ####`this.file(filename)` @@ -246,7 +246,7 @@ If you want to create a path to a file in your module folder, use the `file()` m ####`this.updateDom(speed)` ***speed* Number** - Optional. Animation speed in milliseconds.
-Whenever your module need to be updated, call the `updateDom(speed)` method. It requests the MagicMirror core to update it's dom object. If you define the speed, the content update will be animated, but only if the content will realy change. +Whenever your module need to be updated, call the `updateDom(speed)` method. It requests the MagicMirror core to update its dom object. If you define the speed, the content update will be animated, but only if the content will really change. As an example: the clock modules calls this method every second: @@ -265,7 +265,7 @@ start: function() { ***notification* String** - The notification identifier.
***payload* AnyType** - Optional. A notification payload.
-If you want to send a notification to all other modules, use the `sendNotification(notification, payload)`. All other modules will receive the message via the [notificationReceived](#notificationreceivednotification-payload-sender) method. In that case, the sender is automaticly set to the instance calling the sendNotification method. +If you want to send a notification to all other modules, use the `sendNotification(notification, payload)`. All other modules will receive the message via the [notificationReceived](#notificationreceivednotification-payload-sender) method. In that case, the sender is automatically set to the instance calling the sendNotification method. **Example:** ````javascript @@ -276,7 +276,7 @@ this.sendNotification('MYMODULE_READY_FOR_ACTION', {foo:bar}); ***notification* String** - The notification identifier.
***payload* AnyType** - Optional. A notification payload.
-If you want to send a notification to the node_helper, use the `sendSocketNotification(notification, payload)`. Only the node_helper of this module will recieve the socket notification. +If you want to send a notification to the node_helper, use the `sendSocketNotification(notification, payload)`. Only the node_helper of this module will receive the socket notification. **Example:** ````javascript @@ -287,7 +287,7 @@ this.sendSocketNotification('SET_CONFIG', this.config); ***speed* Number** - Optional, The speed of the hide animation in milliseconds. ***callback* Function** - Optional, The callback after the hide animation is finished. -To hide a module, you can call the `hide(speed, callback)` method. You can call the hide method on the module instance itselve using `this.hide()`, but of course you can also hide an other module using `anOtherModule.hide()`. +To hide a module, you can call the `hide(speed, callback)` method. You can call the hide method on the module instance itself using `this.hide()`, but of course you can also hide another module using `anOtherModule.hide()`. **Note 1:** If the hide animation is canceled, for instance because the show method is called before the hide animation was finished, the callback will not be called.
**Note 2:** If the hide animation is hijacked (an other method calls hide on the same module), the callback will not be called.
@@ -297,7 +297,7 @@ To hide a module, you can call the `hide(speed, callback)` method. You can call ***speed* Number** - Optional, The speed of the show animation in milliseconds. ***callback* Function** - Optional, The callback after the show animation is finished. -To show a module, you can call the `show(speed, callback)` method. You can call the show method on the module instance itselve using `this.show()`, but of course you can also show an other module using `anOtherModule.show()`. +To show a module, you can call the `show(speed, callback)` method. You can call the show method on the module instance itself using `this.show()`, but of course you can also show another module using `anOtherModule.show()`. **Note 1:** If the show animation is canceled, for instance because the hide method is called before the show animation was finished, the callback will not be called.
**Note 2:** If the show animation is hijacked (an other method calls show on the same module), the callback will not be called.
@@ -345,7 +345,7 @@ var NodeHelper = require("node_helper"); module.exports = NodeHelper.create({}); ```` -Of course, the above helper would not do anything usefull. So with the information above, you should be able to make it a bit more sophisticated. +Of course, the above helper would not do anything useful. So with the information above, you should be able to make it a bit more sophisticated. ### Available module instance properties @@ -389,7 +389,7 @@ This is a link to the IO instance. It will allow you to do some Socket.IO magic. This method is called when a node helper gets instantiated. In most cases you do not need to subclass this method. ####`start()` -This method is called when all node helper are loaded an the system is ready to boot up. The start method is a perfect place to define any additional module properties: +This method is called when all node helpers are loaded and the system is ready to boot up. The start method is a perfect place to define any additional module properties: **Example:** ````javascript @@ -400,12 +400,12 @@ start: function() { ```` ####`socketNotificationReceived: function(notification, payload)` -With this method, your node helper can receive notifications form your modules. When this method is called, it has 2 arguments: +With this method, your node helper can receive notifications from your modules. When this method is called, it has 2 arguments: - `notification` - String - The notification identifier. - `payload` - AnyType - The payload of a notification. -**Note:** The socket connection is established as soon as the module sends it's first message using [sendSocketNotification](thissendsocketnotificationnotification-payload). +**Note:** The socket connection is established as soon as the module sends its first message using [sendSocketNotification](thissendsocketnotificationnotification-payload). **Example:** ````javascript @@ -416,15 +416,15 @@ socketNotificationReceived: function(notification, payload) { ### Module instance methods -Each node helper has some handy methods which can be helpfull building your module. +Each node helper has some handy methods which can be helpful building your module. ####`this.sendSocketNotification(notification, payload)` ***notification* String** - The notification identifier.
***payload* AnyType** - Optional. A notification payload.
-If you want to send a notification to all your modules, use the `sendSocketNotification(notification, payload)`. Only the module of your module type will recieve the socket notification. +If you want to send a notification to all your modules, use the `sendSocketNotification(notification, payload)`. Only the module of your module type will receive the socket notification. -**Note:** Since all instances of you module will receive the notifications, it's your task to make sure the right module responds to your messages. +**Note:** Since all instances of your module will receive the notifications, it's your task to make sure the right module responds to your messages. **Example:** ````javascript @@ -447,10 +447,10 @@ To make a selection of all currently loaded module instances, run the `MM.getMod #####`.withClass(classnames)` -***classnames* String or Array** - The class names on which you want to filer. +***classnames* String or Array** - The class names on which you want to filter. **Returns Array** - An array with module instances.
-If you want to make a selection based on one ore more class names, use the withClass method on a result of the `MM.getModules()` method. The argument of the `withClass(classname)` method can be an array, or space separated string. +If you want to make a selection based on one or more class names, use the withClass method on a result of the `MM.getModules()` method. The argument of the `withClass(classname)` method can be an array, or space separated string. **Examples:** ````javascript @@ -476,7 +476,7 @@ var modules = MM.getModules().exceptWithClass(['classname1','classname2']); ***module* Module Object** - The reference to a module you want to remove from the results. **Returns Array** - An array with module instances.
-If you to remove a specific module instance from a selection based on a classname, use the exceptWithClass method on a result of the `MM.getModules()` method. This can be helpfull if you want to select all module instances except the instance of your module. +If you to remove a specific module instance from a selection based on a classname, use the exceptWithClass method on a result of the `MM.getModules()` method. This can be helpful if you want to select all module instances except the instance of your module. **Examples:** ````javascript From 5edf377f4b030ebf2dfffcce23c7b081c1cb514e Mon Sep 17 00:00:00 2001 From: Harri Kapanen Date: Fri, 30 Sep 2016 20:44:53 +0300 Subject: [PATCH 8/8] Finnish translation --- CHANGELOG.md | 1 + translations/fi.json | 28 ++++++++++++++++++++++++++++ translations/translations.js | 1 + 3 files changed, 30 insertions(+) create mode 100644 translations/fi.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 74cb3f7e..3f40dec2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [2.1.0] - Unreleased ### Added +- Finnish translation. - Method to overwrite the module's header. [See documentation.](https://github.com/MichMich/MagicMirror/tree/develop/modules#getheader) - Option to limit access to certain IP addresses based on the value of `ipWhitelist` in the `config.js`, default is access from localhost only (Issue [#456](https://github.com/MichMich/MagicMirror/issues/456)) diff --git a/translations/fi.json b/translations/fi.json new file mode 100644 index 00000000..f370e41c --- /dev/null +++ b/translations/fi.json @@ -0,0 +1,28 @@ +{ + /* GENERAL */ + "LOADING": "Lataa …", + + /* CALENDAR */ + "TODAY": "Tänään", + "TOMORROW": "Huomenna", + "RUNNING": "Meneillään", + "EMPTY": "Ei tulevia tapahtumia.", + + /* WEATHER */ + "N": "P", + "NNE": "PPI", + "NE": "PI", + "ENE": "IPI", + "E": "I", + "ESE": "IEI", + "SE": "EI", + "SSE": "EEI", + "S": "E", + "SSW": "EEL", + "SW": "EL", + "WSW": "LEL", + "W": "L", + "WNW": "LPL", + "NW": "PL", + "NNW": "PPL" +} diff --git a/translations/translations.js b/translations/translations.js index 2a458ef2..09036efc 100644 --- a/translations/translations.js +++ b/translations/translations.js @@ -9,6 +9,7 @@ var translations = { "en" : "translations/en.json", // English "nl" : "translations/nl.json", // Dutch "de" : "translations/de.json", // German + "fi" : "translations/fi.json", // Suomi "fr" : "translations/fr.json", // French "fy" : "translations/fy.json", // Frysk "es" : "translations/es.json", // Spanish