Personal Website With JS Terminal Emulator
LIVE DEMO: https://tjzimmerman.com
DOCKER CONTAINER: https://hub.docker.com/r/zimmertr/personal-website/
- Use docker-compose file found here: https://github.com/zimmertr/Personal-Website-With-JS-Terminal-Emulator/blob/master/Docker/docker-compose.yaml in conjuction with the docker container found here: https://hub.docker.com/r/zimmertr/personal-website/
- Make sure you create these files so Docker doesn't auto-create them as directories.
/Weatherpy/weather.txt: Can be a blank file as long as it is mounted RW. Will be overwritten every 3 minutes with new data starting at t+3M.
- Drop your personal files in
/Files/and they will be available at
Dedicated Server Deployment
- Deploy Apache webserver; install perl, perl-cgi, snmpwalk, nslookup
- Copy cgi scripts to
- Enable execution of CGI scripts.
- Install JackWink's WeatherPy: https://github.com/JackWink/Weather
- Create wunderground api token, add cron to update weather txt file periodically.
Terminal Command Information
Each command has an included manpage that can be accessed with
man >command<. Some of my favorite commands are
Health can be used to query my internal servers for their system & resource information and
Status can be used to evaluate the up/down status of each of my servers. For example, try executing
health janus. (Janus is the hostname of one of my internal servers.)
Full list of supported commands:
|about||Return information about myself|
|clear||Clear the text area|
|echo||Write arguements to STDOUT|
|health||Query a specific server for it's health|
|help||List all tjsh commands to STDOUT|
|history||Display previously executed commands|
|ifconfig||Display server network information|
|man||Display the manual page for a command|
|nslookup||Query an internet name server for info|
|ping||Send an ICMP request to a server|
|status||Show the up/down status of all servers|
|weather||Show a weather report for the servers location|
How does it work?
The application is quite simple. An event handler is spawned by
shell.js that listens for STDINN. When a query is detected, the string in the
input field is parsed and stored as a variable. It is then compared against a whitelist of commands. If a match is detected, one of two things will happen.
- If the command is simple enough in nature,
- If the command is complex or involves communication with my internal network, then a separate cgi script is chainloaded to complete the task.
The resulting output is then returned to the terminal as STDOUT/STDERR. After a command has finished executing, the terminal enters the
cleanup phase. This is used to scroll the output box to the end of STDOUT/STDERR in the event that it takes up more lines than are available. The
input field is then purged of the executed command and a new line is inserted following the output to prepare for another command.
Some other notable things:
- The application supports moderate error handling for both server-side and PEBKAC issues. - The browser's local storage is leveraged to persist a .tjsh_history file, of sorts. for `history`. - The vertical size of the outbox box can be adjusted by dragging the bottom right corner up and down.
Is this safe?
I think so. Any commands that interact with my internal network are matched against a whitelist first. If a match is found, a separate script is then chainloaded by the server and the output is sent back to the server. If anyone wants to help me with pentesting or XSS I would really appreciate the opportunity for a learning experience. Feel free to email me at email@example.com if interested.
If you haven't seen the Family Guy .gif poking fun at CSS with Peter adjusting the blinds on a window, you should go Google it now. I won't pretend to be a web developer, so my CSS is pretty lousy. I've tried my best to make this website mobile friendly but it is still less dynamic than desired. Much help would be appreciated in this area.
Plans for future improvement
Some ideas I have for improvement are:
1. Merging the shell prompt and the outbput box into a single field to better mimic the aesthetic of a true terminal shell. 2. Making commands async to the browser to avoid page hangs. 3. Penetration testing. Including sanitization and encryption of input/output. 4. Expanding local storage to create an artifical `filesystem` so that I can support commands like `ls`, `touch`, `mkdir`, & `cat`. 5. Writing my own weather script to query NOAA so that I don't have to rely on weatherpy. 6. Migration from leveraging CGI scripts in the backend to a full web API for my domain. More secure, dynamic, and efficient. 7. Progress indication for commands that take several seconds to execute. Such as incrememntal dots. `. . . .`| 8. Fix bug with nslookup where an entry not found and the result passed back is not null. But rather "Can't find...". Fail clause for command is prepared for null and, therefore, will never display. 9. Allow `health` to accept a second parameter so that a community string can be passed. 10. Make `weather` command perform API call on demand. Rather than on a cron. So as to alleviate load on Wundergroun's Server. 11. Make `echo` trim off double quotes when a message is echoed like such: echo "test". Current output would be "test" instead of test. 12. Error handling for `health` isn't perfect. Try executing `healthd janus` for example. I don't even know how to describe why it's like that.
Requirements to run:
- A webserver - Perl (For the execution of provided CGI scripts) - Provided CGI scripts placed in /var/www/cgi-bin/ - weatherpy: https://github.com/JackWink/Weather (For obtaining weather information) - Cronjob to update weather every minute: */5 * * * * /var/www/getWeather.sh