├── .gitignore
├── LICENSE
├── README.md
├── app.js
├── assets
├── browserconfig.xml
├── css
│ ├── main.css
│ └── uikit.min.css
├── img
│ ├── android-chrome-192x192.png
│ ├── android-chrome-512x512.png
│ ├── apple-touch-icon.png
│ ├── favicon-16x16.png
│ ├── favicon-32x32.png
│ ├── favicon.ico
│ ├── mstile-144x144.png
│ ├── mstile-150x150.png
│ ├── mstile-310x150.png
│ ├── mstile-310x310.png
│ ├── mstile-70x70.png
│ └── safari-pinned-tab.svg
├── js
│ ├── main.js
│ ├── uikit-icons.min.js
│ └── uikit.min.js
└── site.webmanifest
├── boardcontrol
├── config
└── default.json5
├── package-lock.json
├── package.json
├── screenshot
├── UI_desktop.png
└── UI_mobile.png
└── views
└── index.ejs
/.gitignore:
--------------------------------------------------------------------------------
1 | # Specify filepatterns you want git to ignore.
2 | node_modules/
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 lexb2
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Board Control
2 |
3 | ## Overview
4 |
5 | Control and monitor any GNU/Linux or MacOs system from a Web UI using customizable bash commands to do action or display information. This allow to have a quick look on what is going on the system and perform any action on it without having to start a ssh session (Headless board) or interrupt your favorite movie playing (HTPC).
6 |
7 | Mostly suited to work over local network on development board (Raspberry Pi / Orange Pi / BeagleBone..) or Linux based HTPC. The webUI can be used from a desktop or a phone.
8 |
9 | Mobile (command result cleared) | Desktop (command result display)
10 | :-------------------------:|:-------------------------:
11 |  | 
12 |
13 | ## Requirements
14 |
15 | BoardControl uses Node.js with a few modules. This allow to run it within minutes on any system without having to install and configure a classic web server.
16 |
17 | ## Install Node.js
18 |
19 | > Please refer to the latest installation guide on Node.js website:
20 | > https://nodejs.org/en/download/package-manager/
21 | > or check below for Debian and Ubuntu based Linux distributions
22 |
23 | Install Node.js 8 (LTS) on Debian and Ubuntu based Linux distributions
24 |
25 | ```bash
26 | curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
27 | sudo apt-get install -y nodejs
28 | ```
29 |
30 | Alternatively, for Node.js 9 (Current version):
31 |
32 | ```bash
33 | curl -sL https://deb.nodesource.com/setup_9.x | sudo -E bash -
34 | sudo apt-get install -y nodejs
35 | ```
36 |
37 | ## Get BoardControl
38 |
39 | ```bash
40 | git clone https://github.com/lexb2/BoardControl.git
41 | ```
42 |
43 | ## Use BoardControl
44 |
45 | #### Start one time as user
46 |
47 | ```bash
48 | node BoardControl/app.js
49 | ```
50 |
51 | The following message should be displayed:
52 |
53 | > "BoardControl started and listening on port 8081"
54 |
55 | At this point BoardControl runs with your user rights, it means the commands that required root access won't work.
56 |
57 | #### Automatically run at startup as root
58 |
59 | Install Forever globally to allow the program to run continuously.
60 | https://www.npmjs.com/package/forever
61 |
62 | ```bash
63 | sudo npm install forever -g
64 | ```
65 |
66 | The commands below copy BoardControl in /opt.
67 | All modification of the configuration should be done here.
68 | You can choose another location but if you do so, don't forget to update the `APP` value in `/etc/init.d/boardcontrol` to indicate the right path.
69 |
70 | ```bash
71 | sudo cp -R BoardControl/ /opt
72 | sudo cp /opt/BoardControl/boardcontrol /etc/init.d/boardcontrol
73 | sudo chmod +x /etc/init.d/boardcontrol
74 | sudo update-rc.d boardcontrol defaults
75 | sudo service boardcontrol start
76 | ```
77 |
78 | #### Access BoardControl
79 |
80 | Simply browse:
81 | http://localhost:8081
82 | if you installed it locally,
83 | or
84 | http://ipAdressOfTheMachine:8081
85 |
86 |
87 | #### Configure BoardControl
88 |
89 | BoardControl is customisable using the file `default.json`
90 | located in `BoardControl/config/`.
91 |
92 |
93 | > Some characters need to be escaped for JSON:
94 | > " (Double quote) is replaced with \"
95 | > \ (Backslash) is replaced with \\
96 | > See https://realguess.net/2016/07/29/escaping-in-json-with-backslash/
97 |
98 | `commands` define the actions that can be done using the UI button.
99 |
100 | Field | Description
101 | --- | ---
102 | label | button label display on the website
103 | nickname | internal code of the commands, must be unique, without space or special character
104 | exec | the bash command to execute, result will be shown on website
105 |
106 | `informations` define the information that are always display at the bottom of the webpage.
107 |
108 | Field | Description
109 | --- | ---
110 | label | header label
111 | exec | the bash command to execute, result will be shown on website
112 |
113 | ```json
114 | {
115 | "config": {
116 | "listeningPort": 8081,
117 | "pageTitle": "Board control",
118 | "commands": [
119 | {
120 | "label": "Run my command",
121 | "nickname": "mycommand",
122 | "exec": "time"
123 | },
124 | {
125 | "label": "Run my awesome script",
126 | "nickname": "myscript",
127 | "exec": "/path/to/my/./script.sh"
128 | }
129 | ],
130 | "informations": [
131 | {
132 | "label": "Some information 1",
133 | "exec": "free -h"
134 | },
135 | {
136 | "label": "Some information 2",
137 | "exec": "ls /"
138 | }
139 | ]
140 | }
141 | }
142 | ```
143 |
144 | After updating the configuration, BoardControl need to be restarted
145 |
146 | ```bash
147 | sudo service boardcontrol restart
148 | ```
149 |
150 | #### Config example
151 |
152 | ```json
153 | {
154 | "config": {
155 | "listeningPort": 8081,
156 | "pageTitle": "BoardControl",
157 | "commands": [
158 | {
159 | "label": "Shutdown",
160 | "nickname": "shutdown",
161 | "exec": "poweroff"
162 | },
163 | {
164 | "label": "Reboot",
165 | "nickname": "reboot",
166 | "exec": "reboot"
167 | },
168 | {
169 | "label": "List files",
170 | "nickname": "ls",
171 | "exec": "ls /home"
172 | },
173 | {
174 | "label": "Run script",
175 | "nickname": "myscript",
176 | "exec": "/path/to/my/./script.sh"
177 | }
178 | ],
179 | "informations": [
180 | {
181 | "label": "Disk free space",
182 | "exec": "df -h | grep 'data\\|root\\|Size'"
183 | },
184 | {
185 | "label": "Free ram",
186 | "exec": "free -h"
187 | },
188 | {
189 | "label": "Top cpu process",
190 | "exec": "ps -eo pid,comm,%cpu,%mem --sort=-%cpu | head -n 5"
191 | },
192 | {
193 | "label": "Uptime",
194 | "exec": "uptime"
195 | },
196 | {
197 | "label": "Public IP address",
198 | "exec": "curl -s http://checkip.dyndns.org/ | sed 's/[a-zA-Z<>/ :]//g'"
199 | },
200 | {
201 | "label": "Local IP address",
202 | "exec": "ifconfig | grep -E \"([0-9]{1,3}\\.){3}[0-9]{1,3}\" | grep -v 127.0.0.1 | awk '{ print $2 }' | cut -f2 -d: | head -n1"
203 | }
204 |
205 | ]
206 | }
207 | }
208 | ```
209 |
210 | ## Disclaimer
211 | This software comes with no warranty, it doesn't feature any authentification system and run as root as per installation guide below. Please use only on a trusted local network and do not expose this server to the internet, else anyone could take control your machine (hopefully only with the commands you defined).
212 |
213 | ## Uninstall
214 |
215 | sudo update-rc.d boardcontrol remove
216 | sudo rm /etc/init.d/boardcontrol
217 |
218 | And simply delete BoardControl folder (in /opt as per installation guide)
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 | // Set working dir the directory of the main app
2 | process.chdir(__dirname);
3 |
4 | var http = require('http');
5 | var url = require('url');
6 | var exec = require('child_process').exec;
7 | var express = require('express');
8 | var config = require('config');
9 | var ejs = require('ejs');
10 |
11 | var app = express();
12 |
13 | var config = config.get('config');
14 |
15 | // Get static file direclty from assets directory (Express)
16 | app.use(express.static('assets/'));
17 |
18 | app.get('/', function (req, res) {
19 | res.render('index.ejs', {
20 | links: config.links,
21 | commands: config.commands,
22 | pageTitle: config.pageTitle
23 | });
24 | });
25 |
26 | app.get('/info', function (req, res) {
27 | var informations = config.informations;
28 | var infoResults = new Array()
29 | var i;
30 |
31 | function create_child(i) {
32 | var child = exec(informations[i].exec, function (error, stdout, stderr) {
33 | //console.log("order know in callback " + i + " with PID "+ child.pid);
34 |
35 | //Need to store result on the corresponding command using order/i match.
36 | var index = infoResults.findIndex(x => x.order === i);
37 | infoResults[index].result = stdout;
38 | infoResults[index].status = "done";
39 |
40 | // Return full results only when all async exec are done
41 | if (infoResults.filter(x => x.status == "done").length == informations.length) {
42 | res.json(infoResults);
43 | }
44 | });
45 | return child;
46 | }
47 |
48 | for (i = 0; i < informations.length; i++) {
49 | var created_child = create_child(i);
50 | //Need to store the PID after creating the child process to match the results with the corresponding command.
51 | var infoResult = {};
52 | infoResult["order"] = i;
53 | infoResult["label"] = informations[i].label;
54 | infoResult["result"] = "";
55 | infoResult["status"] = "todo";
56 | infoResults.push(infoResult);
57 | //console.log("order know in external loop " + i + " with PID "+ created_child.pid);
58 | }
59 | });
60 |
61 | app.get('/cmd/:requestedPath', function (req, res) {
62 | var command = config.commands.filter(x => x.nickname === req.params.requestedPath).shift();
63 | if (command) {
64 | var execCmd = command.exec;
65 | child = exec(execCmd, function (error, stdout, stderr) {
66 | var result = { status: (error ? "failure" : "success"), stdout: stdout, stderr: stderr };
67 | res.json(result);
68 | });
69 | }
70 | else {
71 | res.send('No command name found matching with the request "' + req.params.requestedPath + '"');
72 | }
73 | });
74 |
75 | console.log('BoardControl started and listening on port ' + config.get('listeningPort'));
76 | app.listen(config.get('listeningPort'));
77 |
78 |
--------------------------------------------------------------------------------
/assets/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |