Skip to content

Optional config to require a login to access the terminal. #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,24 +37,30 @@
<h1><a href="https://github.com/syntaxseed/terminalfaker">Terminal Faker Demo</a></h1>

<div id="terminal">
<div id="login">

</div>
<p class="hidden">
<span class="prompt"></span>
<span contenteditable="true" class="input" autocorrect="off" autocapitalize="none" autocomplete="off"> </span>
</p>
</div>

<script src="js/bundle.min.js"></script>
<!-- The above minified bundle contains:
<!-- <script src="js/bundle.min.js"></script>-->
<!-- The above minified bundle contains:-->
<script src="js/src/terminal.js"></script>
<script src="js/src/boot.js"></script>
<script src="js/src/crypto.js"></script>
<script src="js/src/system.js"></script>-->
<script src="js/src/system.js"></script>
<script src="js/filesystem.js"></script>
<script src="js/commands.js"></script>

<script>
// Whether to use the longer boot load screen. If this is missing, defaults to true.
var useBootLoader = true;
var useLoginProtection = true;
var validUsername = 'admin';
var validPassword = 'admin';

// Set the command prompt style:
var customPrompt = function () { return "guest@TermFake ("+Terminal.path+") $ ";};
Expand Down
203 changes: 155 additions & 48 deletions js/src/terminal.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ var Terminal = (function () {
var KEY_UP = 38,
KEY_DOWN = 40,
KEY_TAB = 9,
KEY_ENTER = 13,
KEY_BACKSPACE = 8,
MAX_HISTORY = 20;

//var path ="/";
Expand Down Expand Up @@ -221,6 +223,91 @@ var Terminal = (function () {

// Terminal functions

self.loginToTerminal = function (terminal) {
if (!self.useLoginProtection) return;

setTimeout(function() {
var loginElement = document.getElementById("login");
var usernameContainerElement = document.createElement('div');
var passwordContainerElement = document.createElement('div');

function createLabeledInput(baseId, label, value = '') {
var labelElement = document.createElement('span');
labelElement.setAttribute('id', baseId + '-label');
labelElement.innerHTML = label;

var inputElement = document.createElement('input');
inputElement.setAttribute('id', baseId);
inputElement.classList.add('labeled-input');
inputElement.value = value;

return [labelElement, inputElement];
}

var [usernameLabelElement, usernameElement] = createLabeledInput('login-username', 'Login: ');
var [passwordLabelElement, passwordElement] = createLabeledInput('login-password', 'Password: ', '');

usernameElement.addEventListener('keypress', function (e) {
if (self.isLoggedIn || e.keyCode != KEY_ENTER) return;

e.preventDefault();

var password = [];

document.getElementById('login-username').setAttribute('disabled', 'true');

passwordElement.addEventListener('keydown', function(e) {
if (self.isLoggedIn) return;
if (e.which === KEY_BACKSPACE) {
password.pop();
}
});

passwordElement.addEventListener('keypress', function(e) {
if (self.isLoggedIn) return;

e.preventDefault();

if (e.keyCode != KEY_ENTER) {
password.push(String.fromCharCode(e.which));
} else {
var username = document.getElementById('login-username').value;
var passwordString = password.join('');

var loginWelcomeMessageElement = document.createElement('p');
loginElement.append(loginWelcomeMessageElement);
/* TODO validate username and password */
if (username === self.validUsername && passwordString === self.validPassword) {
loginWelcomeMessageElement.innerText = 'You are logged in as ' + username;

setTimeout(function() {
self.isLoggedIn = true;
self.initPrompt(terminal);
}, 0)
} else {
loginWelcomeMessageElement.innerText = 'Failed to log in. Refresh the page and try again';
}
}
});

passwordContainerElement.append(passwordLabelElement);
passwordContainerElement.append(passwordElement);

loginElement.append(passwordContainerElement);

passwordElement.focus();
});

usernameContainerElement.append(usernameLabelElement);
usernameContainerElement.append(usernameElement);

loginElement.append(usernameContainerElement);
loginElement.append(passwordContainerElement);

usernameElement.focus();
}, useBootLoader? bootMessageLines.length * 500 : 500);
};

self.bootTerminalStart = function (terminal) {

var defaultLine = "Type 'help' to get started.";
Expand Down Expand Up @@ -391,84 +478,104 @@ var Terminal = (function () {
return true;
};

self.initPrompt = function(elem) {
if (self.useLoginProtection && !self.isLoggedIn) return;

elem.querySelector(".prompt").innerHTML = self.customPrompt();
elem.querySelector(".input").focus();
};

self.init = function (elem, commands, customPrompt) {
self.commands = commands;
self.customPrompt = customPrompt;
self.useLoginProtection = typeof useLoginProtection !== 'undefined' && useLoginProtection;
self.validUsername = typeof validUsername !== 'undefined' && validUsername ? validUsername : '';
self.validPassword = typeof validPassword !== 'undefined' && validPassword ? validPassword : '';
self.isLoggedIn = false;

if (self.useLoginProtection && (!self.validUsername || !self.validPassword)) {
throw new Error('Valid username or valid password are not defined in index.html!');
}

self.initSession();

elem.addEventListener("keydown", function (event) {
if (event.keyCode == KEY_TAB) {
var prompt = event.target;
var suggestions = autoCompleteInput(prompt.textContent.replace(/\s+/g, ""));

if (suggestions.length == 1) {
prompt.textContent = suggestions[0];
var range = document.createRange();
var sel = window.getSelection();
range.setStart(prompt.childNodes[0], suggestions[0].length);
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
if ((self.useLoginProtection && self.isLoggedIn) || !self.useLoginProtection) {
if (event.keyCode == KEY_TAB) {
var prompt = event.target;
var suggestions = autoCompleteInput(prompt.textContent.replace(/\s+/g, ""));

if (suggestions.length == 1) {
prompt.textContent = suggestions[0];
var range = document.createRange();
var sel = window.getSelection();
range.setStart(prompt.childNodes[0], suggestions[0].length);
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
}

event.preventDefault(true);
return false;
}

event.preventDefault(true);
return false;
}
});

elem.addEventListener("keyup", function (event) {
if (self.historyIndex < 0) return;
browseHistory(event.target, event.keyCode);
if ((self.useLoginProtection && self.isLoggedIn) || !self.useLoginProtection) {
if (self.historyIndex < 0) return;
browseHistory(event.target, event.keyCode);
}
});

elem.addEventListener("keypress", function (event) {
var prompt = event.target;
if (event.keyCode != 13) return false;

var enteredComand = prompt.textContent.trim();
if ((self.useLoginProtection && self.isLoggedIn) || !self.useLoginProtection) {
var prompt = event.target;
if (event.keyCode != 13) return false;

// Split entered command by spaces, but not spaces in quotes.
var input = enteredComand.match(/(?=\S)[^"\s]*(?:"[^\\"]*(?:\\[\s\S][^\\"]*)*"[^"\s]*)*/g);
var enteredComand = prompt.textContent.trim();

if (input == null) {
resetPrompt(elem, prompt, false);
event.preventDefault();
return;
}
// Split entered command by spaces, but not spaces in quotes.
var input = enteredComand.match(/(?=\S)[^"\s]*(?:"[^\\"]*(?:\\[\s\S][^\\"]*)*"[^"\s]*)*/g);

// Remove surrounding quotes if any.
input = input.map(function (e) {
if (e.charAt(0) === '"' && e.charAt(e.length - 1) === '"') {
return e.substr(1, e.length - 2);
} else {
return e;
if (input == null) {
resetPrompt(elem, prompt, false);
event.preventDefault();
return;
}
});

if (input[0]) {
if (input[0].toLowerCase() in self.commands) {
runCommand(elem, input[0].toLowerCase(), input);
updateHistory(prompt.textContent);
} else {
elem.innerHTML += input[0] + ": command not found";
// Remove surrounding quotes if any.
input = input.map(function (e) {
if (e.charAt(0) === '"' && e.charAt(e.length - 1) === '"') {
return e.substr(1, e.length - 2);
} else {
return e;
}
});

if (input[0]) {
if (input[0].toLowerCase() in self.commands) {
runCommand(elem, input[0].toLowerCase(), input);
updateHistory(prompt.textContent);
} else {
elem.innerHTML += input[0] + ": command not found";
}
}
}

// Reset the prompt, and the given array of command also clear the screen.
resetPrompt(elem, prompt, (['clear', 'reboot'].indexOf(input[0].toLowerCase()) >= 0));
event.preventDefault();
// Reset the prompt, and the given array of command also clear the screen.
resetPrompt(elem, prompt, (['clear', 'reboot'].indexOf(input[0].toLowerCase()) >= 0));
event.preventDefault();
}
});

elem.querySelector(".prompt").innerHTML = self.customPrompt();
elem.querySelector(".input").focus();
self.loginToTerminal(elem);
self.initPrompt(elem);

self.term = elem;

// Run the custom boot loader, unless disabled.
//if ((typeof useBootLoader === 'undefined') || useBootLoader) {
self.bootTerminalStart(document.getElementById("terminal"));
self.bootTerminalStart(elem);
//}

return self;
Expand Down
13 changes: 13 additions & 0 deletions terminal.css
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,19 @@ the font size as it's quite small.
display: inline-block;
}

#terminal .labeled-input {
height: 1em;
min-width: 3em;
outline-color: transparent;
border: none;
display: inline-block;
font-size: inherit;
font-weight: inherit;
font-family: inherit;
color: inherit;
background: transparent;
}

#terminal .prompt{
color:#00ff99;
}
Expand Down