Browse Source

Merge pull request #7 from codefeathers/develop

`up v. 0.2.0` Alpha release
tags/v0.2.0 v0.2.0
Muthu Kumar 7 years ago
committed by GitHub
parent
commit
803977783a
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 45
      .eslintrc.json
  2. 5
      .vscode/settings.json
  3. 46
      CODE_OF_CONDUCT.md
  4. 13
      Changelog.md
  5. 21
      LICENSE
  6. 29
      README.md
  7. 31
      actions/createProxyServer.js
  8. 48
      actions/createStaticServer.js
  9. 38
      actions/killALL.js
  10. 18
      actions/killAllConfirm.js
  11. 16
      actions/killServer.js
  12. 16
      actions/listServers.js
  13. 1542
      assets/tlds.txt
  14. 136
      build/defaultNginx.conf
  15. 8
      build/fetchTLDS.js
  16. 94
      index.js
  17. 1534
      package-lock.json
  18. 14
      package.json
  19. 63
      utils/isFQDN.js
  20. 10
      utils/isIP.js
  21. 56
      utils/listFile.js
  22. 7
      utils/nginxConf.js
  23. 43
      utils/nginxPath.js
  24. 6
      utils/nginxReload.js
  25. 9
      utils/parseToInt.js
  26. 16
      utils/removeFromArray.js
  27. 33
      utils/requirements.js
  28. 63
      utils/validate.js

45
.eslintrc.json

@ -1,21 +1,28 @@
{ {
"env": { "env": {
"node": true "node": true,
}, "es6": true
"extends": "eslint:recommended", },
"rules": { "extends": "eslint:recommended",
"no-console": "off", "rules": {
"indent": [ "no-console": "off",
"error", "indent": [
"tab" "error",
], "tab"
"linebreak-style": [ ],
"error", "linebreak-style": [
"unix" "error",
], "unix"
"semi": [ ],
"error", "semi": [
"always" "error",
] "always"
} ],
"prefer-const": "error",
"prefer-destructuring": "error",
"no-var": "error",
"strict": "error",
"eol-last": "error",
"max-len": "error"
}
} }

5
.vscode/settings.json

@ -0,0 +1,5 @@
{
"editor.insertSpaces": false,
"editor.tabSize": 4,
"files.eol": "\n"
}

46
CODE_OF_CONDUCT.md

@ -0,0 +1,46 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at contact@thefeathers.in. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

13
Changelog.md

@ -0,0 +1,13 @@
# Changelog / Version history
## `up` v. 0.2.0
Changelog:
- Under the hood BREAKING changes. Working directories change.
- `/var/www/` to `/etc/up-serve/static/`
- `/etc/nginx/sites-available/` to `/etc/nginx/conf.d`
- `up static|proxy <domain>` adds the server to `/etc/up-serve/servers.up` list.
- `up kill <domain>` removes server from `servers.up` list.
- `up list` lists available servers from /etc/up-serve/servers.up!
- `up kill-all` destroys all servers and places a `default.conf` in `/etc/nginx/sites-enabled`.

21
LICENSE

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Anu Rahul Nandhan a.k.a Muthu Kumar & CodeFeathers
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

29
README.md

@ -8,17 +8,17 @@
# up # up
> Current version: `up v.0.1.5 (Pre-Alpha)` > Current version: `up v.0.2.0 (Alpha)`
> Notes: `up` has landed in pre-alpha! 🎉 Changelog will be added from `up v.0.2.0` [(Alpha/MVP)](Roadmap.md)\ > Notes: `up` is now in Alpha! 🎉 [(Changelog)](Changelog.md)\
> ⚠️ ❌ `up` is still not ready for use yet! Do not attempt to use this in development or production until alpha! > ⚠️ ❌ `up` is pretty useable so far. If you're testing `up` on a development server, do give us feedback.
**`up`** is a command line application that creates nginx server blocks quickly with a single command. **`up`** is a command line application that creates nginx server blocks quickly with a single command.
## Installation ## Installation
As of now, `up` only supports Debian and Ubuntu based distros. Support for more distros will come soon. Add an issue to bump this process. `up` currently supports nginx mainline and nginx stable on Linux based distros. Support for more distros will come soon. Add an issue to bump this process.
You will need to have [_node JS_](https://nodejs.org) and [_nginx_](https://nginx.org) installed. You will need to have [_node JS_](https://nodejs.org) and [_nginx_](https://nginx.org) installed.
@ -28,23 +28,20 @@ Install `up` from npm:
> `up` is now available as a command. > `up` is now available as a command.
## Commands ## Basic Commands
`up static <domain>` - Create new static server at current folder. Format: `up command <required> [optional]`
`up proxy <domain> <port>` - Create new proxy server listening at said port. - `up static <domain> [outbound port]` - Create new static server at current folder.
- `up proxy <domain> <inbound port> [outbound port]` - Create new proxy server listening at said port.
`up list` - List currently available servers. (Doesn't work yet) - `up list` - List currently available servers.
- `up kill <domain>` - Kill the server for this domain.
`up kill <domain>` - Kill the server for this domain.
## Examples ## Examples
`up static example.com` will serve a static website from current folder. - `up static example.com` will serve a static website from current folder.
- `up proxy example.com 8081` will create a reverse proxy listening at port 8081.
`up proxy example.com 8081` will create a reverse proxy listening at port 8081. - `up kill example.com`
`up kill example.com`
## Contributors, Collaborators, and Guides ## Contributors, Collaborators, and Guides

31
actions/createProxyServer.js

@ -1,14 +1,20 @@
var fs = require('fs-extra'); 'use strict';
var shell = require('shelljs');
var npath = require('../utils/nginxPath'); const fs = require('fs-extra');
var conf = require('../utils/nginxConf'); const shell = require('shelljs');
var nginxReload = require('../utils/nginxReload');
var EOL = require('os').EOL; // \n if used on Linux, \r\n if used on Windows. const npath = require('../utils/nginxPath');
const conf = require('../utils/nginxConf');
const nginxReload = require('../utils/nginxReload');
const { appendToList } = require('../utils/listFile');
const { EOL } = require('os'); // \n if used on Linux, \r\n if used on Windows.
function createProxyServer(domain, inPort, outPort) { function createProxyServer(domain, inPort, outPort) {
fs.outputFileSync((conf(npath.availableSites(), domain, outPort)), outPort = outPort || 80;
shell.mkdir('-p', npath.confD());
fs.outputFileSync((conf(npath.confD(), domain, outPort)),
"server {" + EOL + "server {" + EOL +
" listen " + outPort + ";" + EOL + " listen " + outPort + ";" + EOL +
" listen [::]:" + outPort + ";" + EOL + " listen [::]:" + outPort + ";" + EOL +
@ -25,10 +31,15 @@ function createProxyServer(domain, inPort, outPort) {
" }" + EOL + " }" + EOL +
"}" "}"
); );
shell.mkdir('-p', npath.enabledSites()); // Creates directory if doesn't exist shell.mkdir('-p', npath.confD());
shell.ln('-sf', conf(npath.availableSites(), domain, outPort), conf(npath.enabledSites(), domain, outPort)); // Symlink the conf file from sites-available to sites-enabled shell.mkdir('-p', npath.enabledSites());
// Creates directories if doesn't exist
shell.ln('-sf', conf(npath.confD(), domain, outPort),
conf(npath.enabledSites(), domain, outPort));
// Symlink the conf file from sites-available to sites-enabled
appendToList(domain, outPort, inPort);
nginxReload(); nginxReload();
} }
module.exports = createProxyServer; module.exports = createProxyServer;

48
actions/createStaticServer.js

@ -1,21 +1,27 @@
var fs = require('fs-extra'); 'use strict';
var shell = require('shelljs');
var path = require('path');
var npath = require('../utils/nginxPath'); const fs = require('fs-extra');
var conf = require('../utils/nginxConf'); const shell = require('shelljs');
var nginxReload = require('../utils/nginxReload'); const path = require('path');
var currentPath = path.normalize(process.cwd()); const npath = require('../utils/nginxPath');
var EOL = require('os').EOL; // \n if used on Linux, \r\n if used on Windows. const conf = require('../utils/nginxConf');
const nginxReload = require('../utils/nginxReload');
const { appendToList } = require('../utils/listFile');
const currentPath = path.normalize(process.cwd());
const { EOL } = require('os'); // \n if used on Linux, \r\n if used on Windows.
function createStaticServer(domain, outPort) { function createStaticServer(domain, outPort) {
outPort = outPort || 80; outPort = outPort || 80;
fs.outputFileSync((conf(npath.availableSites(), domain, outPort)), // Gets nginx's paths from nginxPath.js shell.mkdir('-p', npath.confD());
fs.outputFileSync((conf(npath.confD(), domain, outPort)),
// Gets nginx's paths from nginxPath.js
"server {" + EOL + "server {" + EOL +
" listen " + outPort + ";" + EOL + " listen " + outPort + ";" + EOL +
" listen [::]:" + outPort + ";" + EOL + " listen [::]:" + outPort + ";" + EOL +
" root " + npath.webRoot() + domain + ";" + EOL + " root " + npath.webRoot() + domain + "." + outPort + ";" + EOL +
" index index.html index.htm;" + EOL + " index index.html index.htm;" + EOL +
"" + EOL + "" + EOL +
" server_name " + domain + ";" + EOL + " server_name " + domain + ";" + EOL +
@ -24,14 +30,22 @@ function createStaticServer(domain, outPort) {
" }" + EOL + " }" + EOL +
"}" "}"
); );
shell.mkdir('-p', npath.enabledSites()); // Creates directory if doesn't exist shell.mkdir('-p', npath.enabledSites());
shell.rm('-rf', conf(npath.enabledSites(), domain, outPort)); // Removes domain from sites-enabled if exists // Creates directories if doesn't exist
shell.ln('-sf', conf(npath.availableSites(), domain, outPort), conf(npath.enabledSites(), domain, outPort)); // Symlink the conf file from sites-available to sites-enabled shell.rm('-rf', conf(npath.enabledSites(), domain, outPort));
shell.rm('-rf', npath.webRootDomain(domain, outPort)); // Removes domain from webroot if exists // Removes domain from sites-enabled if exists
shell.mkdir('-p', npath.webRoot()); // Creating the nginx www path if it doesn't exist so symlink doesn't fail shell.ln('-sf', conf(npath.confD(), domain, outPort),
shell.ln('-sf', currentPath, npath.webRootDomain(domain, outPort)); // Symlink current directory to nginx's web root conf(npath.enabledSites(), domain, outPort));
// Symlink the conf file from confD to sites-enabled
shell.rm('-rf', npath.webRootDomain(domain, outPort));
// Removes domain from webroot if exists
shell.mkdir('-p', npath.webRoot());
// Creating the nginx www path if it doesn't exist so symlink doesn't fail
shell.ln('-sf', currentPath, npath.webRootDomain(domain, outPort));
// Symlink current directory to nginx's web root
appendToList(domain, outPort);
nginxReload(); nginxReload();
} }
module.exports = createStaticServer; module.exports = createStaticServer;

38
actions/killALL.js

@ -0,0 +1,38 @@
'use strict';
const shell = require('shelljs');
const { EOL } = require('os');
const npath = require('../utils/nginxPath');
const conf = require('../utils/nginxConf');
function killALL () {
shell.rm('-Rf', npath.serversBakUp);
shell.mv(npath.serversUp(), npath.serversBakUp());
shell.rm('-Rf', npath() + "sites-available");
shell.rm('-Rf', npath.confD());
shell.rm('-Rf', npath.enabledSites());
shell.rm('-Rf', npath.webRoot());
shell.mkdir('-p', npath.confD());
shell.mkdir('-p', npath.enabledSites());
shell.mkdir('-p', npath.webRoot());
shell.cp('./build/defaultNginx.conf', conf(npath.confD()));
// Create the default.conf file
shell.ln('-sf', npath.confD() + "default.conf",
npath.enabledSites() + "default.conf");
// Symlink the default.conf file from confD to sites-enabled
console.log("All servers were killed and reverted to default.");
console.log(EOL + [
"A backup of your old servers.up is " +
"saved in /etc/up-serve/servers.bak.up.",
"Check this if you need to."
].join(EOL) + EOL);
}
function noKill () {
console.log("\nkill-all was interrupted by user.");
}
module.exports.kill = killALL;
module.exports.noKill = noKill;

18
actions/killAllConfirm.js

@ -0,0 +1,18 @@
'use strict';
const readlineSync = require('readline-sync');
const killALL = require('./killALL').kill;
const { noKill } = require('./killALL');
function killAllConfirm() {
console.log("\nThis action will destroy all nginx servers and return "
+ "to default configuration.");
if (readlineSync.keyInYN("Are you sure you want to do this?")) {
killALL();
}
else {
noKill();
}
}
module.exports = killAllConfirm;

16
actions/killServer.js

@ -1,15 +1,19 @@
var shell = require('shelljs'); 'use strict';
var npath = require('../utils/nginxPath'); const shell = require('shelljs');
var conf = require('../utils/nginxConf');
var nginxReload = require('../utils/nginxReload'); const npath = require('../utils/nginxPath');
const conf = require('../utils/nginxConf');
const nginxReload = require('../utils/nginxReload');
const { removeFromList } = require('../utils/listFile');
function killServer(domain, outPort) { function killServer(domain, outPort) {
shell.rm('-rf', conf(npath.enabledSites(), domain, outPort)); shell.rm('-rf', conf(npath.enabledSites(), domain, outPort));
shell.rm('-rf', conf(npath.availableSites(), domain, outPort)); shell.rm('-rf', conf(npath.confD(), domain, outPort));
shell.rm('-rf', npath.webRootDomain(domain, outPort)); shell.rm('-rf', npath.webRootDomain(domain, outPort));
removeFromList(domain, outPort);
nginxReload(); nginxReload();
} }
module.exports = killServer; module.exports = killServer;

16
actions/listServers.js

@ -0,0 +1,16 @@
'use strict';
const { readServers } = require('../utils/listFile');
const prettyjson = require('prettyjson');
const { EOL } = require('os');
function listServers() {
const serversList = readServers();
if(serversList) console.log(EOL + prettyjson.render(serversList) + EOL);
else console.log(EOL +
"No servers were found! Create some using `up`!" +
EOL);
}
module.exports = listServers;

1542
assets/tlds.txt

File diff suppressed because it is too large

136
build/defaultNginx.conf

@ -0,0 +1,136 @@
#user nobody;
#Defines which Linux system user will own and run the Nginx server
worker_processes 1;
#Referes to single threaded process. Generally set to be equal to the number of CPUs or cores.
#error_log logs/error.log; #error_log logs/error.log notice;
#Specifies the file where server logs.
#pid logs/nginx.pid;
#nginx will write its master process ID(PID).
events {
worker_connections 1024;
# worker_processes and worker_connections allows you to calculate maxclients value:
# max_clients = worker_processes * worker_connections
}
http {
include mime.types;
# anything written in /opt/nginx/conf/mime.types is interpreted as if written inside the http { } block
default_type application/octet-stream;
#
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
# If serving locally stored static files, sendfile is essential to speed up the server,
# But if using as reverse proxy one can deactivate it
#tcp_nopush on;
# works opposite to tcp_nodelay. Instead of optimizing delays, it optimizes the amount of data sent at once.
#keepalive_timeout 0;
keepalive_timeout 65;
# timeout during which a keep-alive client connection will stay open.
#gzip on;
# tells the server to use on-the-fly gzip compression.
server {
# You would want to make a separate file with its own server block for each virtual domain
# on your server and then include them.
listen 80;
#tells Nginx the hostname and the TCP port where it should listen for HTTP connections.
# listen 80; is equivalent to listen *:80;
server_name localhost;
# lets you doname-based virtual hosting
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
#The location setting lets you configure how nginx responds to requests for resources within the server.
root html;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root html;
# index index.html index.htm;
# }
#}
# HTTPS server
#
#server {
# listen 443 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
#}
}

8
build/fetchTLDS.js

@ -0,0 +1,8 @@
'use strict';
const https = require('https');
const fs = require('fs-extra');
const file = fs.createWriteStream("./assets/tlds.txt");
https.get("https://data.iana.org/TLD/tlds-alpha-by-domain.txt",response =>
response.pipe(file));

94
index.js

@ -1,66 +1,104 @@
#!/usr/bin/env node #!/usr/bin/env node
'use strict';
const { EOL } = require('os');
// Requiring npm modules // Requiring npm modules
var program = require('commander'); const program = require('commander');
var chalk = require('chalk'); const chalk = require('chalk');
//var fs = require('fs-extra');
// Requiring Actions
const createProxyServer = require('./actions/createProxyServer');
const createStaticServer = require('./actions/createStaticServer');
const killServer = require('./actions/killServer');
const listServers = require('./actions/listServers');
const killAllConfirm = require('./actions/killAllConfirm');
// Requiring utils // Requiring utils
var validate = require('./utils/validate'); const validate = require('./utils/validate');
var requirements = require('./utils/requirements'); const requirements = require('./utils/requirements');
// Requiring Actions // Check for requirements such as OS version and nginx install.
var createProxyServer = require('./actions/createProxyServer'); // Throw and exit if requirements not found.
var createStaticServer = require('./actions/createStaticServer'); // #Roadmap: Add ability to satisfy any possible requirements.
var killServer = require('./actions/killServer');
// Check for requirements such as OS version and nginx install. Throw and exit if requirements not found. #Roadmap: Add ability to satisfy any possible requirements. requirements(); // Comment in development and uncomment this line in production.
requirements(); // Comment in development and uncomment this line in production. This should check whether the OS is compatible with this version of `up` // This should check whether the OS is compatible with this version of `up`
program program
.version('0.1.5'); .version('0.2.0');
program program
.command('static <domain> [outPort]') .command('static <domain> [outPort]')
.description('Create a static server at this folder.') .description('Create a static server at this folder.')
.action(function (domain, outPort) { //If outport is not given, 80 is set as default. Later, change this default to reflect nginx's settings. .action(function (domain, outPort) {
outPort = outPort || "80"; // This is a string because regex needs to validate it. // If outport is not given, 80 is set as default.
if (!validate(domain, outPort)) return; //Validates domain and outport, and if invalid, throws and returns. // Later, change this default to reflect nginx's settings.
outPort = outPort || "80";
// This is a string because regex needs to validate it.
if (!validate(domain, outPort)) return;
// Validates domain and outport, and if invalid, throws and returns.
createStaticServer(domain, outPort); createStaticServer(domain, outPort);
if (outPort != "80" || "443") domain = domain + ":" + outPort; if (outPort != "80" || "443") domain = domain + ":" + outPort;
console.log("Done! Your static server has been set up!\nPoint your domain to this server and check " + chalk.cyan(domain) + " to verify!"); console.log(EOL + [
"Done! Your static server has been set up!",
"Point your domain to this server and check " +
chalk.cyan(domain) +
" to verify!"
].join(EOL));
}); });
program program
.command('proxy <domain> <inPort> [outPort]') .command('proxy <domain> <inPort> [outPort]')
.description('Create a proxy server, listening at port number.') .description('Create a proxy server, listening at port number.')
.action(function (domain, inPort, outPort) { //Inbound port is necessary, but outbound is set to 80 by default. Again, will change this to reflect nginx's settings. .action(function (domain, inPort, outPort) {
outPort = outPort || "80"; // This is a string because regex needs to validate it. // Inbound port is necessary, but outbound is set to 80 by default.
// Again, will change this to reflect nginx's settings.
outPort = outPort || "80";
// This is a string because regex needs to validate it.
if (!validate(domain, inPort, outPort)) return; if (!validate(domain, inPort, outPort)) return;
createProxyServer(domain, inPort, outPort); createProxyServer(domain, inPort, outPort);
if (outPort != "80" || "443") domain = domain + ":" + outPort; if (outPort != "80" || "443") domain = domain + ":" + outPort;
console.log("Done! Your reverse proxy server has been set up!\nPoint your domain to this server and check " + chalk.cyan(domain) + " to verify!"); console.log(EOL + [
"Done! Your reverse proxy server has been set up!",
"Point your domain to this server and check " +
chalk.cyan(domain) +
" to verify!"
].join(EOL));
}); });
program program
.command('list') .command('list')
.description('List all available servers.') .description('List all available servers.')
.action(function () { .action(function () {
// Stuff happens here listServers();
}); });
program program
.command('kill <domain> [ourPort]') .command('kill <domain> [ourPort]')
.description('Kill a server.') .description('Kill a server.')
.action(function (domain, outPort) { .action(function (domain, outPort) {
outPort = outPort || "80"; // This is a string because regex needs to validate it. outPort = outPort || "80";
// This is a string because regex needs to validate it.
killServer(domain, outPort); killServer(domain, outPort);
console.log("\nDone! Your server has been killed!\n"); console.log(EOL + "Done! Your server has been killed!"+ EOL);
});
program
.command('kill-all')
.description('Warning! Will completely kill all servers and reset nginx')
.action(function() {
//new Promise(resolve => killed\killAllConfirm();
killAllConfirm();
}); });
program program
.command('*') // This should pick invalid commands, but it doesn't, yet. .command('*') // This should pick invalid commands, but it doesn't, yet.
.action(function () { .action(function () {
console.log("Invalid command. Type " + chalk.cyan('up --help') + " for help."); console.log(EOL + "Invalid command. Type " +
chalk.cyan('up --help') + " for help." + EOL);
}); });
// Adds custom help text to the automatically generated help. // Adds custom help text to the automatically generated help.
@ -68,13 +106,19 @@ program.on('--help', function () {
console.log(''); console.log('');
console.log(' Usage:'); console.log(' Usage:');
console.log(''); console.log('');
console.log(' ', chalk.yellow('$ up'), chalk.cyan('static'), chalk.blue('domain-name')); console.log(' ',
chalk.yellow('$ up'),
chalk.cyan('static'),
chalk.blue('domain-name'));
console.log(' Set up a static server at domain-name'); console.log(' Set up a static server at domain-name');
console.log(''); console.log('');
console.log(' ', chalk.yellow('$ up'), chalk.cyan('proxy'), chalk.blue('domain-name port-number')); console.log(' ',
chalk.yellow('$ up'),
chalk.cyan('proxy'),
chalk.blue('domain-name port-number'));
console.log(' Set up a proxy server listening at port-number'); console.log(' Set up a proxy server listening at port-number');
console.log(''); console.log('');
}); });
// Parses commands passed to `up` and chooses one of the above commands. // Parses commands passed to `up` and chooses one of the above commands.
program.parse(process.argv); program.parse(process.argv);

1534
package-lock.json

File diff suppressed because it is too large

14
package.json

@ -1,10 +1,11 @@
{ {
"name": "up-serve", "name": "up-serve",
"version": "0.1.5", "version": "0.2.0",
"description": "A cli tool to quickly create and manage nginx server blocks.", "description": "A cli tool to quickly create and manage nginx server blocks.",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1",
"build": "node ./build/fetchTLDS"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@ -30,7 +31,12 @@
"chalk": "^2.3.0", "chalk": "^2.3.0",
"commander": "^2.11.0", "commander": "^2.11.0",
"fs-extra": "^4.0.2", "fs-extra": "^4.0.2",
"shelljs": "^0.7.8", "prettyjson": "^1.2.1",
"validator": "^9.1.1" "prompt": "^1.0.0",
"readline-sync": "^1.4.7",
"shelljs": "^0.7.8"
},
"devDependencies": {
"eslint": "^4.10.0"
} }
} }

63
utils/isFQDN.js

@ -0,0 +1,63 @@
// Module courtesy of TRGWII
// Original: https://github.com/trgwii/isFQDN
'use strict';
const fs = require('fs-extra');
const path = require('path');
// Official list of TLDs should be fetched from:
// https://data.iana.org/TLD/tlds-alpha-by-domain.txt
// You must have received a copy of the list along with `up`
// Run `npm run build` to update the cached list
function isFQDN(domain) {
// Importing and parsing `tlds.txt` file
const tldspath = path.join(__dirname, '/../assets/tlds.txt');
const tlds = fs.readFileSync(tldspath, 'utf8')
.split(/[\r\n]+/)
.filter(x => !x.startsWith('#'));
if (domain.length > 253) {
return false;
}
const labels = domain.split('.').reverse();
if (labels.length < 2) {
return false;
}
const [ tld ] = labels;
if (!tlds.includes(tld.toUpperCase())) {
return false;
}
for (const label of labels) {
const len = label.length;
if (len > 63 || len === 0) {
return false;
}
for (let i = 0; i < len; i++) {
const char = label[i];
if ((i === 0 || i === len - 1) && char === '-') {
return false;
}
if (!char.match(/^[a-zA-Z0-9-]$/)) {
return false;
}
}
}
return true;
}
module.exports = isFQDN;

10
utils/isIP.js

@ -1,14 +1,16 @@
'use strict';
// Parses a string, and returns true if it is an IP Address. // Parses a string, and returns true if it is an IP Address.
function isIP(str) { function isIP(str) {
var segments = str const segments = str
.split(".") .split(".")
.map(Number); .map(Number);
if (!segments.length === 4) { if (!segments.length === 4) {
return false; return false;
} }
for(var i = 0; i < segments.length; i++) { for(let i = 0; i < segments.length; i++) {
var segment = segments[i]; const segment = segments[i];
if (Number.isNaN(segment)) { if (Number.isNaN(segment)) {
return false; return false;
} }
@ -22,4 +24,4 @@ function isIP(str) {
return true; return true;
} }
module.exports = isIP; module.exports = isIP;

56
utils/listFile.js

@ -0,0 +1,56 @@
'use strict';
const { EOL } = require('os');
const fs = require('fs-extra');
const removeFromArray = require('./removeFromArray');
const listFilePath = require('./nginxPath').serversUp;
function appendToList(domain, outPort, inPort) {
inPort = inPort || undefined;
let jsonFile = { "domains": [] };
const domBlock = {
"domain": domain,
"outPort": outPort
};
if (!inPort) {
domBlock.type = "static";
} else {
domBlock.type = "proxy";
domBlock.inPort = inPort;
}
if (fs.existsSync(listFilePath())) {
const jsonBuffer = JSON.parse(fs.readFileSync(listFilePath()));
jsonFile.domains = removeFromArray(jsonBuffer.domains, domain, outPort);
}
jsonFile.domains.push(domBlock);
jsonFile = JSON.stringify(jsonFile, null, '\t');
fs.writeFileSync(listFilePath(), jsonFile);
}
function removeFromList (domain, outPort) {
if (fs.existsSync(listFilePath())) {
let jsonFile = { "domains": [] };
const jsonBuffer = JSON.parse(fs.readFileSync(listFilePath()));
jsonFile.domains = removeFromArray(jsonBuffer.domains, domain, outPort);
jsonFile = JSON.stringify(jsonBuffer, null, '\t');
fs.writeFileSync(listFilePath(), jsonFile);
}
else console.log(EOL + "No servers were created using `up` yet." + EOL);
}
function readServers () {
const serversList = JSON.parse(fs.readFileSync(listFilePath()));
if(!serversList.domains[0]) return undefined;
return serversList;
}
module.exports.appendToList = appendToList;
module.exports.readServers = readServers;
module.exports.removeFromList = removeFromList;

7
utils/nginxConf.js

@ -1,7 +1,10 @@
// Simple function that takes a path and domain name, concatenates them with ".conf" and returns it. 'use strict';
// Simple function that takes a path and domain name,
// concatenates them with ".conf" and returns it.
function conf(path, domain, outPort) { function conf(path, domain, outPort) {
return (path + domain + "." + outPort + ".conf"); return (path + domain + "." + outPort + ".conf");
} }
module.exports = conf; module.exports = conf;

43
utils/nginxPath.js

@ -1,27 +1,50 @@
// These functions just return paths. Later, these should be modified to poll from nginx's config. 'use strict';
var available = "/etc/nginx/sites-available/"; // These functions just return paths.
var enabled = "/etc/nginx/sites-enabled/"; // Later, these should be modified to poll from nginx's config.
var wwwRoot = "/var/www/";
function availableSites() { const npath = "/etc/nginx/";
return available; const enabled = npath + "sites-enabled/";
const confDpath = npath + "conf.d/";
const upPath = "/etc/up-serve/";
const wwwRoot = upPath + "static/";
const serverListPath = upPath + "servers";
function nginxPath() {
return npath;
} }
function enabledSites() { function enabledSites() {
return enabled; return enabled;
} }
function confD() {
return confDpath;
}
function webRoot() { function webRoot() {
return wwwRoot; return wwwRoot;
} }
function webRootDomain(domain, outPort) { function webRootDomain(domain, outPort) {
var rootWithDomain = wwwRoot + domain + "." + outPort; const path = wwwRoot + domain + "." + outPort;
return rootWithDomain; return path;
}
function serversUp() {
const path = serverListPath + ".up";
return path;
}
function serversBakUp() {
const path = serverListPath + ".bak.up";
return path;
} }
module.exports.availableSites = availableSites; module.exports = nginxPath;
module.exports.confD = confD;
module.exports.enabledSites = enabledSites; module.exports.enabledSites = enabledSites;
module.exports.webRoot = webRoot; module.exports.webRoot = webRoot;
module.exports.webRootDomain = webRootDomain; module.exports.webRootDomain = webRootDomain;
module.exports.serversUp = serversUp;
module.exports.serversBakUp = serversBakUp;

6
utils/nginxReload.js

@ -1,4 +1,6 @@
var execSync = require('child_process').execSync; 'use strict';
const { execSync } = require('child_process');
function nginxReload() { function nginxReload() {
execSync('service nginx reload', function (error, stdout, stderr) { execSync('service nginx reload', function (error, stdout, stderr) {
@ -11,4 +13,4 @@ function nginxReload() {
}); });
} }
module.exports = nginxReload; module.exports = nginxReload;

9
utils/parseToInt.js

@ -1,8 +1,11 @@
// Parse an input string and return a number if it is an integer. If it's a float, string, or array, return undefined. 'use strict';
// Parse an input string and return a number if it is an integer.
// If it's a float, string, or array, return undefined.
function parseToInt(inputString) { function parseToInt(inputString) {
var parsing = /^\d+$/.exec(inputString); const parsing = /^\d+$/.exec(inputString);
return (parsing || [])[0]; return (parsing || [])[0];
} }
module.exports = parseToInt; module.exports = parseToInt;

16
utils/removeFromArray.js

@ -0,0 +1,16 @@
'use strict';
function removeFromArray (arr, dom, port) {
let shouldDelete = [];
for(let i = 0; i < arr.length; i++)
if((arr[i].domain == dom) && (arr[i].outPort == port))
shouldDelete = [true, i];
if (shouldDelete[0]) {
arr.splice(shouldDelete[1], 1);
}
return arr;
}
module.exports = removeFromArray;

33
utils/requirements.js

@ -1,23 +1,40 @@
var shell = require('shelljs'); 'use strict';
var chalk = require('chalk');
const { EOL } = require('os');
const shell = require('shelljs');
const chalk = require('chalk');
function requirements() { function requirements() {
// Detect Linux or BSD // Detect Linux or BSD
var isLin = /^linux|^bsd/.test(process.platform); const isLin = /^linux|^bsd/.test(process.platform);
// Throw if OS is not Linux or BSD. This should be changed to throw if not Debian based distro. Eventually, we can add more exceptions as `up` handles more cases. // Throw if OS is not Linux or BSD.
// This should be changed to throw if not Debian based distro.
// Eventually, we can add more exceptions as `up` handles more cases.
if(!isLin) { if(!isLin) {
shell.echo("\nThis is not a Linux or freeBSD distribution. This tool not written for this distro. Please raise an issue at " + chalk.cyan("https://github.com/codefeathers/up-serve") + " if you want `up` to be ported for your distro"); shell.echo(EOL +
"This is not a Linux or freeBSD distribution. " +
"This tool not written for this distro. " +
"Please raise an issue at " +
chalk.cyan("https://github.com/codefeathers/up-serve") +
" if you want `up` to be ported for your distro");
shell.exit(1);
}
// Check if sudo
if (process.getuid() != 0) {
console.log("`up` requires root privileges to work. Please use `sudo up <command>`");
shell.exit(1); shell.exit(1);
} }
// Throw if Nginx is not found // Throw if Nginx is not found
if (!shell.which('nginx')) { if (!shell.which('nginx')) {
shell.echo('I need nginx to work. Install nginx first. https://nginx.org/'); shell.echo(
'I need nginx to work. Install nginx first. https://nginx.org/');
shell.exit(1); shell.exit(1);
} }
} }
module.exports = requirements; module.exports = requirements;

63
utils/validate.js

@ -1,9 +1,12 @@
var validator = require('validator'); 'use strict';
var parseToInt = require('./parseToInt');
var isIP = require('./isIP'); const { EOL } = require('os');
const parseToInt = require('./parseToInt');
const isIP = require('./isIP');
// Using Validator // Using Validator
var isDomain = validator.isFQDN; const isDomain = require('./isFQDN');
function validate(domain, inPort, outPort) { function validate(domain, inPort, outPort) {
// //
@ -11,15 +14,27 @@ function validate(domain, inPort, outPort) {
outPort = outPort || 80; outPort = outPort || 80;
// Error messages // Error messages
var domainInvalidMsg = ["\nPlease use a domain name instead of an IP address.", "\nDomain is not valid. Please use a valid domain name."]; const domainInvalidMsg = [
var portInvalidMsg = ["\nPort should be a number.", "\nPort should be a number from 1 and 65535."]; EOL + "Please use a domain name instead of an IP address.",
EOL + "Domain is not valid. Please use a valid domain name."
];
const portInvalidMsg = [
EOL + "Port should be a number.",
EOL + "Port should be a number from 1 and 65535."
];
// ARGV returns a string as input. Port numbers should be parsed to int to validate them. If validation fails, these will return undefined and will fail the subsequent test. // ARGV returns a string as input.
var validInPort = parseToInt(inPort); // Port numbers should be parsed to int to validate them.
var validOutPort = parseToInt(outPort); // If validation fails, these will return undefined and
// will fail the subsequent test.
const validInPort = parseToInt(inPort);
const validOutPort = parseToInt(outPort);
// The value of isInvalid will be returned back. If none of the `if`s are true, the default value `true` is returned `domain`, `inPort` and `outPort` are considered validated. // The value of isInvalid will be returned back.
var isValid = true; // If none of the `if`s are true, the default
// value `true` is returned `domain`, `inPort` and `outPort` are considered
// validated.
let isValid = true;
// Throw if IP is given instead of domain name. // Throw if IP is given instead of domain name.
if (isIP(domain)) { if (isIP(domain)) {
@ -33,32 +48,42 @@ function validate(domain, inPort, outPort) {
return isValid = false; return isValid = false;
} }
// Enter if `inPort` is not defined. This happens for `up static` where no inbound ports are required. // Enter if `inPort` is not defined.
// This happens for `up static` where no inbound ports are required.
if (typeof inPort == undefined) { if (typeof inPort == undefined) {
if (!validOutPort) { if (!validOutPort) {
console.log(portInvalidMsg[0]); // `outPort` is not an integer. console.log(portInvalidMsg[0]); // `outPort` is not an integer.
return isValid = false; return isValid = false;
} }
if (!(validOutPort > 0 && validOutPort <= 65535)) { if (!(validOutPort > 0 && validOutPort <= 65535)) {
console.log(portInvalidMsg[1]); // `outPort` is not within port range. console.log(portInvalidMsg[1]);
// `outPort` is not within port range.
return isValid = false; return isValid = false;
} }
} }
// Enter if `inPort` is defined. This happens for `up proxy` where inbound port is required. // Enter if `inPort` is defined. This happens for `up proxy` where
// inbound port is required.
if (typeof inPort !== undefined) { if (typeof inPort !== undefined) {
if (!validInPort || !validOutPort) { if (!validInPort || !validOutPort) {
console.log(portInvalidMsg[0]); // Either `inPort` or `outPort` is not an integer. console.log(portInvalidMsg[0]);
// Either `inPort` or `outPort` is not an integer.
return isValid = false; return isValid = false;
} }
if (typeof outPort !== undefined) { if (typeof outPort !== undefined) {
if (!((validInPort > 0 && validInPort <= 65535) && (validOutPort > 0 && validOutPort <= 65535))) { if (!(
console.log(portInvalidMsg[1]); // Either `inPort` or `outPort` are not within port range. (validInPort > 0 && validInPort <= 65535) &&
(validOutPort > 0 && validOutPort <= 65535)
)) {
console.log(portInvalidMsg[1]);
// Either `inPort` or `outPort` are not within port range.
return isValid = false; return isValid = false;
} }
} }
return isValid; // If any of the `if`s were true, `isInvalid = false`. If not, `isInvalid = true`. return isValid;
// If any of the `if`s were true, `isInvalid = false`.
// If not, `isInvalid = true`.
} }
} }
module.exports = validate; module.exports = validate;

Loading…
Cancel
Save