const util = {
history: {
index: 0,
limit: 100
},
printf: function (format, ...args) {
return format.replace(/%[sd]/g, (match) => {
return args.shift();
});
},
isHostname: function (input) {
const hostnameRegex = /^[^:/\s.#?]+\.[^:/\s#?]+|localhost$/;
return hostnameRegex.test(input);
},
isValidIPv4: function (ip) {
const blocks = ip.split('.');
if (blocks.length !== 4) {
return false;
}
for (const block of blocks) {
const numericBlock = parseInt(block, 10);
if (!(numericBlock >= 0 && numericBlock <= 255)) {
return false;
}
}
return true;
},
isValidIPv6: function (ip) {
const blocks = ip.split(':');
if (blocks.length < 8) {
return false;
}
for (const block of blocks) {
if (!/^[0-9A-Fa-f]{1,4}$/.test(block)) {
return false;
}
}
return true;
},
isValidIP: function (ip) {
return isValidIPv4(ip) || isValidIPv6(ip);
},
fetch: async (link, opts = {}) => {
const response = await fetch(link, opts);
if (response.ok) {
const result = await response.json();
return Promise.resolve(result);
} else {
return Promise.reject("Opps!!");
}
},
colorize: function (type) {
},
compare: function (a, b) {
if (a.name < b.name) {
return -1;
}
if (a.name > b.name) {
return 1;
}
return 0;
},
wordBreak: function (str, len = 84) {
const words = str.split(' ');
let currentLine = '';
let lines = [];
for (const word of words) {
if ((currentLine + ' ' + word).length <= len) {
currentLine += (currentLine ? ' ' : '') + word;
} else {
lines.push(currentLine);
currentLine = word;
}
}
if (currentLine) {
lines.push(currentLine);
}
return lines.join('\n');
},
sleep: function (ms) {
return new Promise(resolve => setTimeout(resolve, ms));
},
createName: function (int) {
var n = '';
var c = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (var x = 0; x < int; x++) {
n += c.charAt(util.rand(c.length) - 1);
}
return n;
},
newArray: function (i, s) {
i = new Array(i);
for (let x = 0; x < i.length; x++) {
i[x] = s;
}
return i;
},
MDParser: function (text) {
let output = text;
output = output.replace(/^### (.*$)/gim, '<h3>$1</h3>');
output = output.replace(/^## (.*$)/gim, '<h2>$1</h2>');
output = output.replace(/^# (.*$)/gim, '<h1>$1</h1>');
output = output.replace(/``(.*?)``/gm, '<code>$1</code>');
output = output.replace(/`(.*?)`/gm, '<code>$1</code>');
output = output.replace(/\[(.*?)\]\((.*?) "(.*?)"\)/gm, '<a href="$2" title="$3">$1</a>');
output = output.replace(/<http(.*?)\>/gm, '<a href="http$1">http$1</a>');
output = output.replace(/\[(.*?)\]\(\)/gm, '<a href="$1">$1</a>');
output = output.replace(/\[(.*?)\]\((.*?)\)/gm, '<a href="$2">$1</a>');
output = output.replace(/^[\*|+|-][ |.](.*)/gm, '<ul><li>$1</li></ul>').replace(/<\/ul\>\n<ul\>/g, '\n');
output = output.replace(/^\d[ |.](.*)/gm, '<ol><li>$1</li></ol>').replace(/<\/ol\>\n<ol\>/g, '\n');
output = output.replace(/\*\*\*(.*)\*\*\*/gm, '<b><em>$1</em></b>');
output = output.replace(/\*\*(.*)\*\*/gm, '<b>$1</b>');
output = output.replace(/\*([\w \d]*)\*/gm, '<em>$1</em>');
output = output.replace(/___(.*)___/gm, '<b><em>$1</em></b>');
output = output.replace(/__(.*)__/gm, '<u>$1</u>');
output = output.replace(/_([\w \d]*)_/gm, '<em>$1</em>');
return output.trim();
},
b64: {
en: function (s) {
return btoa(encodeURIComponent(s).replace(/%([0-9A-F]{2})/g, (match, p1) => String.fromCharCode('0x' + p1)));
},
de: function (s) {
return decodeURIComponent(atob(s).split('').map(c => {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
}
},
stringify: function (obj) {
const keyValuePairs = [];
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
const value = obj[key];
const keyValueString = `--${key}='${value}'`;
keyValuePairs.push(keyValueString);
}
}
return keyValuePairs.join("");
},
flatten: function (obj, parentKey, flatObj = {}, keyTransformer = null) {
const defaultKeyTransformer = (key, parentKey) => parentKey ? `${parentKey}[${key}]` : key;
keyTransformer = keyTransformer || defaultKeyTransformer;
for (let key in obj) {
let transformedKey = keyTransformer(key, parentKey);
if (typeof obj[key] == 'object') {
util.flatten(obj[key], transformedKey, flatObj);
} else {
flatObj[transformedKey] = obj[key];
}
}
return flatObj;
},
showProgress: async function (idx, current, total, before = "Progress:", after = "complete") {
const barSize = 40;
const barCharDone = "#";
const barCharTodo = "-";
const barPercentageScale = 2;
// Calculate the progress in percentage
const percent = ((current / total) * 100).toFixed(barPercentageScale);
// The number of done and todo characters
const done = Math.round((barSize * percent) / 100);
const todo = barSize - done;
// Build the done and todo sub-bars
const doneSubBar = barCharDone.repeat(done);
const todoSubBar = barCharTodo.repeat(todo);
// Output the bar
const $container = $("terminal").find(".container");
const $progress = $container.find(`span[data-count="${idx}"]`);
//let idx = $progress.attr("data-count");
$progress
//.removeClass("progress")
//.addClass("progress-"+idx)
.html("")
.html(`${before}: [${doneSubBar}${todoSubBar}] ${percent}% ${after}\n`);
if (total === current) {
//
}
},
mergeOpts: function (obj, ...defs) {
return Object.assign({}, obj, ...defs.reverse(), obj);
},
rand: function (int) {
return Math.floor(Math.random() * int) + 1;
}
};
const DEFAULT_FS = {
"name": "~",
"type": "dir",
"permissions": "rwxr-xr-x",
"modified": "2023-10-20 12:00:00",
"contents": [
{
"name": "bin",
"type": "dir",
"permissions": "rwxr-xr-x",
"modified": "2023-10-20 12:00:00",
"contents": []
},
{
"name": "etc",
"type": "dir",
"permissions": "rwxr-xr-x",
"modified": "2023-10-20 12:00:00",
"contents": [
{
"name": "nginx.conf",
"type": "config",
"permissions": "rw-r--r--",
"modified": "2023-10-20 12:00:00",
"mime": "text/plain",
"contents": "mock nginx configuration content"
},
{
"name": "apache.conf",
"type": "config",
"permissions": "rw-r--r--",
"modified": "2023-10-20 12:00:00",
"mime": "text/plain",
"contents": "mock apache configuration content"
}
]
},
{
"name": "var",
"type": "dir",
"permissions": "rwxr-xr-x",
"modified": "2023-10-20 12:00:00",
"contents": [
{
"name": "log",
"type": "dir",
"permissions": "rwxr-xr-x",
"modified": "2023-10-20 12:00:00",
"contents": [
{
"name": "access.log",
"type": "file",
"permissions": "rw-r--r--",
"modified": "2023-10-20 12:00:00",
"mime": "text/plain",
"contents": "mock access log content"
},
{
"name": "error.log",
"type": "file",
"permissions": "rw-r--r--",
"modified": "2023-10-20 12:00:00",
"mime": "text/plain",
"contents": "mock error log content"
}
]
},
{
"name": "www",
"type": "dir",
"permissions": "rwxr-xr-x",
"modified": "2023-10-20 12:00:00",
"contents": [
{
"name": "index.html",
"type": "file",
"permissions": "rw-r--r--",
"modified": "2023-10-20 12:00:00",
"mime": "text/html",
"contents": "<html><head><title>Welcome to the Webroot</title></head><body><h1>Welcome to the Webroot of your website server</h1></body></html>"
}
]
}
]
},
{
"name": "home",
"type": "dir",
"permissions": "rwxr-xr-x",
"modified": "2023-10-20 12:00:00",
"contents": [
{
"name": "guest",
"type": "dir",
"permissions": "rwxr-xr-x",
"modified": "2023-10-20 12:00:00",
"contents": [
{
"name": "Documents",
"type": "dir",
"permissions": "rwxr-xr-x",
"modified": "2023-10-20 12:00:00",
"contents": [
{
"name": "TermPaper.doc",
"type": "text",
"permissions": "rw-r--r--",
"modified": "2023-10-20 12:00:00",
"mime": "application/msword",
"contents": "Hello World!"
},
]
},
{
"name": "Music",
"type": "dir",
"permissions": "rwxr-xr-x",
"modified": "2023-10-20 12:00:00",
"contents": []
},
{
"name": "Photos",
"type": "dir",
"permissions": "rwxr-xr-x",
"modified": "2023-10-20 12:00:00",
"contents": [
{
"name": "avatar.jpg",
"type": "img",
"permissions": "rw-r--r--",
"modified": "2023-10-20 12:00:00",
"mime": "image/jpeg",
"contents": ""
},
]
},
{
"name": "Videos",
"type": "dir",
"permissions": "rwxr-xr-x",
"modified": "2023-10-20 12:00:00",
"contents": []
},
{
"name": "Downloads",
"type": "dir",
"permissions": "rwxr-xr-x",
"modified": "2023-10-20 12:00:00",
"contents": [
{
"name": "GoogleDrive.zip",
"type": "archive",
"permissions": "rw-r--r--",
"modified": "2023-10-20 12:00:00",
"mime": "application/x-zip-compressed",
"contents": "foo"
},
]
}
]
},
{
"name": "demo",
"type": "dir",
"permissions": "rwxr-xr-x",
"modified": "2023-10-20 12:00:00",
"contents": [
{
"name": "Documents",
"type": "dir",
"permissions": "rwxr-xr-x",
"modified": "2023-10-20 12:00:00",
"contents": []
},
{
"name": "Music",
"type": "dir",
"permissions": "rwxr-xr-x",
"modified": "2023-10-20 12:00:00",
"contents": []
},
{
"name": "Photos",
"type": "dir",
"permissions": "rwxr-xr-x",
"modified": "2023-10-20 12:00:00",
"contents": []
},
{
"name": "Videos",
"type": "dir",
"permissions": "rwxr-xr-x",
"modified": "2023-10-20 12:00:00",
"contents": []
}
]
}
]
}
]
};
class Parser {
/**
* @constructor
* @param {string} command A string representing the command line arguments.
* @returns Parser
*/
constructor(command) {
if (!command || !command.length) {
throw new Error('Parser: command provided is empty.');
}
if (typeof command !== 'string') {
throw new Error('Parser error: input must be of type string!');
}
this.raw = command;
// Split string by space, but keep intact spaces if between quotes
let argv = this.stringToArray(command.replace(/\s{2,}/g, '').replace(/\t|\n/g, ' '));
this.command = argv[0];
this._ = [];
if (argv.length) {
const parsed = this.parse(argv.slice(1));
// If no Object.assign do the old way
if (!Object.assign) {
for (let key in parsed) {
if (parsed.hasOwnProperty(key)) {
this[key] = parsed[key];
}
}
return true;
}
return Object.assign(this, parsed);
}
}
/**
* @method stringToArray()
* - Get a command string
* - split by spaces
* - keep anything within single/double quotes
* @return Array
*/
stringToArray(string) {
return string.match(/[^\s"']+|"([^"]*)"|'([^']*)'/g);
}
/**
* @method parse()
* Parse an array of ARGV to an Object of { flag:value }
*
* Every other value outside of flag is pushed
* in an array in the order of appearance
*
* Flag Type:
* - -f option
* - -f
* - --verboseflag="value stringed"
* - --verboseflag=value
*
* Recursion
* Parse an option and reduce the array size,
* recall until it return the parsed object
*
* @return {Object} Parsed Options
*/
parse(options, parsed = {}) {
console.log(options);
if (!options.length) return parsed;
/**
* Matches a flag starting with only one hyphen
* [-f val] or [-f] standalone boolean
* input passed as ['-p', 'val', ...]
*/
//if (options[0].startsWith('-')) {
// const flags = arg.slice(1).split('');
//flags.forEach((flag) => (parsed.flags[flag] = true));
if (options[0].match(/^\-[^\-].*/)) {
const optionName = options[0].replace('-', '');
/**
* if -f is followd by another flag
* is a booloeadn flag
*/
if (options[1] && options[1].match(/^\-.*/)) {
parsed[optionName] = true;
return this.parse(options.splice(1), parsed);
}
/**
* IF -f as last element
* is a booloeadn flag
*/
if (!options[1]) {
parsed[optionName] = true;
return this.parse(options.splice(1), parsed);
}
parsed[optionName] = options[1];
return this.parse(options.splice(2), parsed);
}
/**
* Matches verbose flag with string
* --flag="val val2"
* input passed as ['--flag', '"val val2"']
*/
if (options[0].match(/^\-{2}.*\=$/)) {
// capture the flag name
const optionName = options[0].match(/--(.*)=/)[1];
// capture the flag value
parsed[optionName] = options[1].replace(/"/g, '');
return this.parse(options.splice(2), parsed);
}
/**
* Matches verbose flag with non spaced value
* --flag=value
* input passed as ['--flag=value]
*/
if (options[0].match(/^\-{2}.*\={1}.*$/)) {
// capture the flag name
const optionName = options[0].match(/\-{2}(.*)=/)[1];
// capture the flag value
parsed[optionName] = options[0].match(/\={1}(.*)/)[1];
return this.parse(options.splice(1), parsed);
}
/**
* Matches verbose flag with no value as a boolean
*/
if (options[0].match(/^\-{2}.*$/)) {
const optionName = options[0].replace('--', '');
/**
* If not followed by options
* OR if followed by options and options is another flag
* then set as boolean verbose flag
*/
if (!options[1] || (options[1] && options[1].match(/^\-{1,}/))) {
parsed[optionName] = true;
return this.parse(options.slice(1), parsed);
}
if (options[1] && !options[1].match(/^\-{1,}/)) {
parsed[optionName] = options[1];
return this.parse(options.slice(2), parsed);
}
}
// If it's not a flag is source/dest path
this['_'].push(options.shift());
return this.parse(options, parsed);
}
}
function VirtualFileSystem() {
let self = this;
this.tree = new TreeStructure();
this.user = 'root';
this.cwd = this.tree.root;
// Define a function to insert JSON data recursively
VirtualFileSystem.prototype.initStructure = function (node, parent) {
let properties = {};
node['size'] = node.type !== "dir" ? node.contents.length : 0;
for (let property in node) {
properties[property] = node[property];
}
properties['uid'] = self.getUid();
properties['modified'] = self.getDate();
properties['user'] = this.user;
properties['group'] = this.user;
const nodeData = this.tree.insert(node.name, parent, properties);
if (node.contents && Array.isArray(node.contents)) {
for (const childData of node.contents) {
self.initStructure(childData, nodeData);
}
}
};
VirtualFileSystem.prototype.toObject = function (node) {
const objNode = {
name: node.key,
type: node.type,
permissions: node.permissions,
modified: node.modified,
};
if (node.children.length > 0) {
objNode.children = node.children.map(child => self.toObject(child));
}
return objNode;
};
VirtualFileSystem.prototype.toJson = function (obj) {
const object = self.toObject(obj);
return JSON.stringify(object, null, 2);
};
VirtualFileSystem.prototype.getUid = function () {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
s4() + '-' + s4() + s4() + s4();
};
VirtualFileSystem.prototype.getDate = function () {
const d = new Date();
let s = ('0' + d.getDate()).slice(-2) + '.';
s += ('0' + (d.getMonth() + 1)).slice(-2) + '.';
s += d.getFullYear() + ' ';
s += ('0' + d.getHours()).slice(-2) + ':';
return s + ('0' + d.getMinutes()).slice(-2);
};
VirtualFileSystem.prototype.mkdir = function (path) {
if (path === undefined) {
throw new TypeError("Missing argument: path");
}
let segments = path.replace(/\/+$/g, "").split("/");
let parent = self._resolve_path(
segments.slice(0, segments.length - 1).join("/")
);
let name = segments[segments.length - 1];
if (parent.find(name).length) {
throw new Error("Name already taken: " + name);
}
this.tree.insert(name, parent, {
permissions: "rwxr-xr-x",
name: name,
modified: self.getDate(),
size: 0,
user: "root",
group: "root",
type: "dir"
});
};
VirtualFileSystem.prototype.rmdir = function (path) {
if (path === undefined) {
throw new TypeError("Missing argument: path");
}
let node = self._resolve_path(path.replace(/\/+$/g, ""));
if (node === this.tree.root) {
throw new Error("You cannot delete the root directory.");
} else if (node.type !== "directory") {
throw new Error("Not a directory: " + node.key);
}
this.tree.delete(node);
let current_path = self._absolute_path(this.cwd);
let node_path = self._absolute_path(node);
if (node_path.match("^" + current_path) && current_path.length) {
this.cwd = node.parent;
}
};
VirtualFileSystem.prototype.cd = function (path) {
if (path === undefined) {
throw new TypeError("Missing argument: path");
}
this.cwd = self._resolve_path(path);
return this.cwd;
};
VirtualFileSystem.prototype.cat = function (mode, path, contents) {
if (path === undefined) {
throw new TypeError("Missing argument: path");
}
let segments = path.replace(/\/+$/g, "").split("/");
let parent = self._resolve_path(segments.slice(0, segments.length - 1).join("/"));
let name = segments[segments.length - 1];
let node = parent.find(name)[0];
if (node && node.type !== "file") {
throw new Error("Not a file: " + path);
} else if (mode.length) {
if (node === undefined) {
node = this.tree.insert(name, parent, {
type: "file",
modified: new Date().getTime(),
size: "",
contents: ""
});
}
node.size = mode === ">" ? new Blob([contents]).size : new Blob([node.contents + contents]).size;
node.contents = mode === ">" ? contents : node.contents + contents;
} else {
if (node === undefined) {
throw new Error("File not found: " + path);
}
return node.contents;
}
};
VirtualFileSystem.prototype.rm = function (path) {
if (path === undefined) {
throw new TypeError("Missing argument: path");
}
let node = self._resolve_path(path.replace(/\/+$/g, ""));
if (node.type !== "file") {
throw new Error("Not a file: " + node.key);
}
this.tree.delete(node);
};
VirtualFileSystem.prototype.rn = function (path, name) {
if (path === undefined) {
throw new TypeError("Missing argument: path");
} else if (name === undefined) {
throw new TypeError("Missing argument: name");
}
let node = self._resolve_path(path);
if (node === this.tree.root) {
throw new Error("You cannot rename the root directory.");
}
let search = node.parent.find(name)[0];
if (search && search.type === node.type) {
throw new Error("Rename failed. Name already taken.");
}
node.key = name;
};
VirtualFileSystem.prototype.cp = function (target, destination) {
if (target === undefined) {
throw new TypeError("Missing argument: target");
} else if (destination === undefined) {
throw new TypeError("Missing argument: destination");
}
target = typeof target === "object" ? target : self._resolve_path(target);
destination = typeof destination === "object" ? destination : self._resolve_path(destination);
let properties = {
type: target.type
};
if (properties.type === "file") {
properties.contents = target.contents;
properties.modified = target.lastMoodified;
properties.size = target.size;
}
let node = this.tree.insert(target.key, destination, properties);
for (let i = 0; i < target.children.length; i++) {
self.cp(target.children[i], node);
}
return node;
};
VirtualFileSystem.prototype.mv = function (target, destination) {
if (target === undefined) {
throw new TypeError("Missing argument: target");
} else if (destination === undefined) {
throw new TypeError("Missing argument: destination");
}
target = typeof target === "object" ? target : self._resolve_path(target);
destination = typeof destination === "object" ? destination : self._resolve_path(destination);
this.tree.delete(target);
return self.cp.call(this, target, destination);
};
VirtualFileSystem.prototype.ls = function (path) {
let node = path === undefined ? this.cwd : self._resolve_path(path);
if (node.type === "directory") {
return node.children;
}
throw new Error("Not a directory: " + path);
};
VirtualFileSystem.prototype.whereis = function (query) {
if (query === undefined) {
throw new framesError("Missing argument: query");
}
return this.tree.search(query);
};
VirtualFileSystem.prototype._resolve_path = function (path) {
path = path.match("^/") ? path : "./" + path;
path = path.split("/");
let parent = path[0].length ? this.cwd : this.tree.root;
for (let i = !path[0].length ? 1 : 0; i < path.length; i++) {
if (path[i] === "..") {
if (parent === this.tree.root) {
throw new Error("No more directories beyond root directory.");
}
parent = parent.parent;
} else if (path[i] !== "." && path[i].length) {
parent = parent.find(path[i])[0];
if (parent === undefined) {
throw new Error("Path not found: " + path.slice(0, i + 1).join("/"));
}
}
}
return parent;
};
VirtualFileSystem.prototype._absolute_path = function (node) {
let path = [];
while (node !== null) {
path.unshift(node.key);
node = node.parent;
}
return path.join("/");
};
};
function TreeStructure() {
this.root = null;
this.insert = function (key, parent, properties) {
if (key === undefined) {
throw new TypeError("Missing argument: key");
}
parent = parent instanceof TreeNode ? [parent] : this.search(parent);
let node = new TreeNode(key, properties);
if (parent === null && !this.root) {
this.root = node;
} else if (parent === null && !!this.root) {
throw new Error("TreeStructure already has a root. Please specify the node's parent.");
} else if (!parent.length) {
throw new Error("Parent node not found.");
} else {
parent[0].insert(node);
}
return node;
};
this.delete = function (node) {
if (node === undefined) {
throw new TypeError("Missing argument: node");
}
let targets = node instanceof TreeNode ? [node] : this.search(node);
if (targets === null || !targets.length) {
throw new Error("Target node not found.");
}
for (let i = 0; i < targets.length; i++) {
let target = targets[i];
if (target === this.root) {
this.root = null;
} else {
target.parent.delete(target);
}
}
};
this.search = function (key) {
return key !== undefined && this.root ? this.root.search(key) : null;
};
this.traverse = function () {
if (this.root !== null) {
let queue = [this.root];
let levels = [];
let level = [];
for (let i = 1, j = 0; queue.length;) {
let pointer = queue.shift();
level.push(pointer);
j += pointer.children.length;
if (!--i) {
i = j;
j = 0;
levels.push(level);
level = [];
}
queue = queue.concat(pointer.children);
}
return levels;
}
return [];
};
}
function TreeNode(key, properties) {
this.key = key;
this.parent = null;
this.children = [];
properties = properties && typeof properties === "object" ? properties : {};
for (let i in properties) {
this[i] = properties[i];
}
this.insert = function (child) {
this.children.push(child);
child.parent = this;
};
this.delete = function (child) {
this.children.splice(this.children.indexOf(child), 1);
};
this.search = function (key) {
let results = this.key.match("^" + key.replace(/\./g, "\\.").replace(/\*/g, ".*") + "$") ? [this] : [];
for (let i in this.children) {
results = results.concat(this.children[i].search(key));
}
return results;
};
this.find = function (key) {
let results = [];
for (let i in this.children) {
if (this.children[i].key.match("^" + key.replace(/\./g, "\\.").replace(/\*/g, ".*") + "$")) {
results.push(this.children[i]);
}
}
return results;
};
}
class Termeditor {
constructor(element, opts) {
let $ = jQuery;
if (!element) return;
let self = this;
this.allowInput = true;
this.secondaryInstance = false;
const _defaults = {
welcome: "<span class=\"host\">TERM[E]DITOR BASH</span>—v1.0\nA good place to start would be to type <span class=\"cmd\">help</span>.",
themes: [
"dark",
"light",
"laserwave",
"nord",
"greyscale",
"dracula",
"nightowl",
"onedark"
],
theme: "onedark"
};
function mergeOptions(obj, ...defs) {
return Object.assign({}, obj, ...defs.reverse(), obj);
}
const $terminal = $(element);
const $container = $("<pre />").addClass("container blink");
$terminal.html($container);
this.options = util.mergeOpts(opts, _defaults);
this.shell = $terminal;
this.container = $container;
this.vfs = new VirtualFileSystem;
this.cwd = this.vfs.cwd;
this.sudo = false;
this.user = "demo";
this.cursor = "$";
this.busy = false;
this.kaliPrompt = false;
let copiedText = null;
let command = "";
this.builtIn = [{
"name": "cd",
"type": "exec",
"mime": "application/x-sharedlib",
"help": "<span class=\"cmd\">cd</span>: [<span class=\"parameter\">dir</span>]\n\tChange the working directory.\n\n\tChange the current working directory to <span class=\"parameter\">dir</span>. The default <span class=\"parameter\">dir</span> is the value\n\tof the <span class=\"info\">$HOME</span> environment variable.\n\n",
"func": function (argv) {
if (argv.help || argv.h) {
const cmd = self.builtIn.find(cmd => cmd.name === 'cd');
self.stdout(true, cmd.help);
return;
}
const dir = argv['_'].join();
if (dir !== undefined) {
let cwd = self.vfs._absolute_path(self.vfs.cwd);
if (cwd === "~") cwd = "/";
if (dir.length === 0 || dir === '.' || (dir === '..' && cwd === '~')) {
return;
}
if (dir === "~") {
self.env.OLDPWD = cwd;
self.vfs.cd("/");
return;
}
if (dir === "/") {
self.env.OLDPWD = cwd;
self.vfs.cd("/");
return;
}
if (dir === "-") {
if (self.env.OLDPWD !== null) {
self.vfs.cd(self.env.OLDPWD !== "~" ? "/" : self.env.OLDPWD);
self.env.OLDPWD = cwd;
return;
} else {
$container.append("-bash: cd: OLDPWD not set");
return;
}
}
if (dir.indexOf("/") !== -1) {
let parts = dir.split("/");
for (let i = 0; i < parts.length; i++) {
if (parts[i] === "..") {
self.vfs.cd('..');
} else {
self.vfs.cd(parts[i]);
}
}
return;
} else if (dir === "..") {
self.env.OLDPWD = cwd;
self.vfs.cd('..');
return;
} else {
self.env.OLDPWD = cwd;
self.vfs.cd(cwd + "/" + dir);
return;
}
} else {
$container.append("bash: cd: Usage: cd [dir]\n\n");
}
}
}, {
"name": "pwd",
"type": "exec",
"mime": "application/x-sharedlib",
"help": "<span class=\"cmd\">pwd</span>:\n\tPrint the working directory.\n\n\tPrints the current working directory.\n\n",
"func": function pwd() {
if (argv.help || argv.h) {
const cmd = self.builtIn.find(cmd => cmd.name === 'pwd');
self.stdout(true, cmd.help);
return;
}
$container.append(self.vfs._absolute_path(self.vfs.cwd) + "\n");
}
}, {
"name": "ls",
"type": "exec",
"mime": "application/x-sharedlib",
"help": "<span class=\"cmd\">ls</span>: [<span class=\"parameter\">options</span>]\n\tList directory contents.\n\n\tList all files and folders in the current working directory.\n\tWith no options, <span class=\"cmd\">ls</span> lists the files contained in the current\n\tdirectory, sorting them seperatly alphabetically.\n\n\tOptions:\n\t -f\tlist only files\n\t -d\tlist only directories\n\n",
"func": function ls(argv) {
if (argv.help || argv.h) {
const cmd = self.builtIn.find(cmd => cmd.name === 'ls');
self.stdout(true, cmd.help);
return;
}
console.log(argv);
function formatNodeLong(node) {
const isDir = node.type === 'dir';
const isLink = node.type === 'link';
let size = isDir ? 0 : node.size.toString().padStart(6, " ");
let colorize = isDir ? util.printf("<span class=\"dir\">%s</span>", node.name) : isLink ? util.printf("<span class=\"dir\">%s</span> -> <span class=\"path\">%s</span>", node.name, node.link) : node.name;
let elem = `${isLink ? node.name + ' -> ' + node.link : node.name}`;
return `${isDir ? 'd' : isLink ? 'l' : '-'}${node.permissions} ${node.user} ${node.group} ${size} ${node.modified} ${colorize}`;
}
let targetNode;
if (argv._.length !== 0) {
targetNode = self.vfs._resolve_path(argv._.join(''));
} else {
targetNode = self.vfs.cwd;
}
let maxLen = 0;
if (targetNode) {
if (argv['d'] && targetNode.type === "dir") {
self.stdout(false, util.wordBreak(targetNode.key));
} else if (targetNode.children) {
self.stdout(true, "total " + targetNode.children.length);
targetNode.children.forEach(node => {
if (argv.a || !node.name.startsWith('.')) {
if (argv.l) {
self.stdout(true, formatNodeLong(node));
} else {
self.stdout(false, node.name.padEnd(node.name.length + 3, " "), "dir");
}
}
});
self.stdout(true);
}
self.stdout(true);
} else {
console.log("Path not found.");
}
}
}, {
"name": "tree",
"type": "exec",
"mime": "application/x-sharedlib",
"help": "<span class=\"cmd\">tree</span>: [<span class=\"parameter\">path</span>] [<span class=\"parameter\">options</span>]\n\tGraphically displays a directory structure.\n\n\tWhen you use the <span class=\"cmd\">tree</span> command each directory name is displayed along\n\twith the names of any subdirectories within it. The structure displayed\n\tby <span class=\"cmd\">tree</span> depends upon which parameters you specify.\n\t\n\tIf you don't specify a path, <span class=\"cmd\">tree</span> displays the tree structure of the\n\tcurrent working directory.\n\n\tOptions:\n\t -f\tDisplay the names of the files in each folder.\n\n",
"func": async function (argv) {
console.log(argv);
if (argv.help || argv.h) {
const cmd = self.builtIn.find(cmd => cmd.name === 'tree');
self.stdout(true, cmd.help);
return;
}
let node = argv._[0] === undefined ? self.vfs.tree.root : self.vfs._resolve_path(argv._[0]);
let level = argv.level === undefined ? 0 : argv.level;
let prefix = argv.prefix === undefined ? "" : argv.prefix;
if (level === 0) {
$container.append(".\n");
}
if (node.type === "dir") {
const children = node.children;
const childCount = children.length;
for (let i = 0; i < childCount; i++) {
const child = children[i];
const directoryName = child.name;
const indentation = prefix + (i === childCount - 1 ? " ┗ ╸" : " ┣ ╸");
$container.append(indentation + directoryName + "\n");
if (child.type === "dir") {
let newPrefix = prefix + (i === childCount - 1 ? " " : " ┃ ");
level++;
let stdin = `tree ${self.vfs._absolute_path(child).slice(1)} --level=${level} --prefix=${newPrefix}`;
await self.execCommand(stdin);
//tree(child, $container, level + 1, prefix + (i === childCount - 1 ? " " : " | "));
}
}
}
}
}, {
"name": "set",
"type": "exec",
"mime": "application/x-sharedlib",
"help": "<span class=\"cmd\">set</span>: [<span class=\"parameter\">key</span>] [<span class=\"parameter\">value</span>]\n\tSet or unset values of shell options.\n\n  Sets or unsets the shell variables by specifying <span class=\"parameter\">key</span> <span class=\"info\">value</span> pairs.\n  If <span class=\"parameter\">key</span> is not specified then defaults to displaying the names and\n  values of shell variables.\n\n",
"func": function set(argv) {
console.log(argv);
if (argv.help || argv.h) {
const cmd = self.builtIn.find(cmd => cmd.name === 'set');
self.stdout(true, cmd.help);
return;
}
let append = "";
if (argv._[0] === undefined) {
Object.keys(self.env)
.sort()
.forEach(function (name, i) {
append += name + "=" + self.env[name] + "\n";
});
append += "\n";
} else {
let key;
if (argv._[1] === undefined) {
$container.append("bash: set: Usage: set [key] [value]\n\n");
return;
}
if (argv._[0].toLowerCase() === "user") {
key = argv._[0].toUpperCase();
self.env[key] = argv._[1];
return;
} else {
key = argv._[0].toUpperCase();
self.env[key] = argv._[1];
}
append += "<span class=\"info\">" + key + "</span> has been set to <span class=\"success\">" + argv._[1] + "</span>\n";
}
$container.append(append);
}
}, {
"name": "dir",
"type": "link",
"link": "/bin/ls",
"mime": "inode/symlink",
"help": "<span class=\"cmd\">dir</span>: [<span class=\"parameter\">dir</span>]\n\tAn alias for <span class='cmd'>ls</span>.\n\n\tShows the contents of <span class=\"parameter\">dir</span>. This command will display certain file attributes\n\tdepending on certain flags being passed.\n\n\tIf <span class=\"parameter\">dir</span> is not specified then defaults to the current working directory.\n\n\tOptions:\n\t -l, --long-format\tdisplay with file attributes\n\t -a, --all\t\tdisplay hidden files including files that start\n\t\t\t\twith '.'\n\n",
"func": function (argv) {
if (argv.help || argv.h) {
const cmd = self.builtIn.find(cmd => cmd.name === 'dir');
self.stdout(true, cmd.help);
return;
}
const cmd = self.builtIn.find(cmd => cmd.name === 'ls');
cmd.func(argv);
}
}, {
"name": "base64",
"type": "exec",
"mime": "application/x-sharedlib",
"help": "<span class=\"cmd\">base64</span>: [<span class=\"parameter\">string</span>] [<span class=\"parameter\">options</span>]\n\tBase64 encode or decode standard input, to standard output.\n\n\tEncode or decode a string using the algorithum as described for\n\tthe Base64 alphabet specified in <a href=\"https://datatracker.ietf.org/doc/html/rfc4648\" target=\"_blank\">RFC 4648, section 4</a>. If no option\n\tis specified then <span class=\"cmd\">base64</span> will default to encoding.\n\n\tOptions:\n\t -e, --encode\tencode the input string\n\t -d, --decode\tdecode the input string\n\n",
"func": function (argv) {
console.log(argv);
if (argv.help || argv.h) {
const cmd = self.builtIn.find(cmd => cmd.name === 'base64');
self.stdout(true, cmd.help);
return;
}
if (argv._.length !== 0) {
let str = argv._.join(" ");
if (str.charAt(0) === '"' || str.charAt(0) === "'") {
str = str.slice(0, 1);
}
if (str.charAt(str.length - 1) === '"' || str.charAt(str.length - 1) === "'") {
str = str.slice(-1);
}
if (argv.d || argv.decode) {
try {
self.stdout(true, util.wordBreak(util.b64.de(str)));
return;
} catch (e) {
self.stdout(true, "bash: base64" + e.toString().substr(e.toString().lastIndexOf(':')));
return;
}
} else {
try {
self.stdout(true, util.wordBreak(util.b64.en(str)));
return;
} catch (e) {
self.stdout(true, "bash: base64" + e.toString().substr(e.toString().lastIndexOf(':')));
return;
}
}
} else {
self.stdout(true, "bash: base64: Usage: base64 [string] [options]\n");
}
}
}, {
"name": "mkdir",
"type": "exec",
"mime": "application/x-sharedlib",
"help": "<span class=\"cmd\">mkdir</span>: [<span class=\"parameter\">dir</span>]\n\tCreate a directory.\n\n\tCreates a folder in the current working directory with the\n\tname specified by the parameter <span class=\"parameter\">dir</span>.\n\n",
"func": function (argv) {
if (argv.help || argv.h) {
const cmd = self.builtIn.find(cmd => cmd.name === 'mkdir');
self.stdout(true, cmd.help);
return;
}
if (argv['_'][0].indexOf("/") !== -1) {
let parts = argv['_'][0].split("/");
for (let i = 0; i < parts.length; i++) {
self.vfs.mkdir(parts[i]);
}
} else {
self.vfs.mkdir(argv['_'][0]);
}
$container.append("\n");
return;
}
}, {
"name": "touch",
"help": "<span class=\"cmd\">touch</span>: [<span class=\"parameter\">file</span>] [<span class=\"parameter\">content</span>]\n\tCreate a file.\n\n\tCreates an empty file in the current working directory with the\n\tname specified by <span class=\"parameter\">file</span>. If <span class=\"parameter\">content</span> is supplied, then creates a\n\tfile with <span class=\"parameter\">content</span> as its content.\n\n",
"func": function (argv) {
if (argv.help || argv.h) {
const cmd = self.builtIn.find(cmd => cmd.name === 'ls');
self.stdout(true, cmd.help);
return;
}
}
}, {
"name": "clear",
"type": "exec",
"mime": "application/x-sharedlib",
"help": "<span class=\"cmd\">clear</span>: [<span class=\"parameter\">options</span>]\n\tClear the terminal.\n\n\tClears the current terminal window. If <span class=\"parameter\">-h</span> is specified\n\tthen also clears the command history.\n\n\tOptions:\n\t -h\tclear command history\n\n",
"func": function (argv) {
if (argv.help || argv.h) {
const cmd = self.builtIn.find(cmd => cmd.name === 'ls');
self.stdout(true, cmd.help);
return;
}
$container.html('');
}
}, {
"name": "whereis",
"type": "exec",
"mime": "application/x-sharedlib",
"help": "<span class=\"cmd\">whereis</span>: [<span class=\"parameter\">options</span>]\n\tLocate the binary, source, and manual-page files for a command.\n\n\tClears the current terminal window. If <span class=\"parameter\">-h</span> is specified\n\tthen also clears the command history.\n\n\tOptions:\n\t -h\tclear command history\n\n",
"func": function (argv) {
if (argv.help || argv.h) {
const cmd = self.builtIn.find(cmd => cmd.name === 'ls');
self.stdout(true, cmd.help);
return;
}
$container.html('');
}
}, {
"name": "help",
"type": "exec",
"mime": "application/x-sharedlib",
"help": "<span class=\"cmd\">help</span>: [<span class=\"parameter\">command</span>]\n\tDisplay a command's help information.\n\n\tShows the help information of the supplied <span class=\"cmd\">command</span>. If no\n\t<span class=\"cmd\">command</span> is specified then shows the help message.\n\n",
"func": function () {
if (arguments[0].help || arguments[0].h) {
const cmd = self.builtIn.find(cmd => cmd.name === 'help');
self.stdout(true, cmd.help);
return;
}
let append = "";
if (arguments[0]["_"].length === 0) {
append += "<span class=\"host\">TERM[E]DITOR BASH</span>, <span class=\"info\">version 1.0-release</span> (" + navigator.platform.replace(' ', '-').replace('_', '-').toLowerCase() + "-gnu)\n";
append += "These shell commands are defined internally. Type <span class=\"cmd\">help</span> to see this list.\n";
append += "Type <span class=\"cmd\">help</span> <span class=\"parameter\">command</span> for help with a particular command.\n\n";
append += "Some of these commands aren't functional yet.\n\n";
append += "Available commands:\n";
const columnWidth = 30; // Fixed width for each column
for (let i = 0; i < commands.length; i++) {
const cmdName = commands[i].name;
const padding = columnWidth - cmdName.length;
const columnText = `<span class="cmd" style="padding-left:3em">${cmdName}</span>${' '.repeat(padding)}`;
append += columnText;
if (i % 2 !== 0) {
append += "\n";
}
}
append += "\n";
} else {
for (let i = 0; i < commands.length; i++) {
if (arguments[0]['_'][0] === commands[i].name) {
append += commands[i].help;
}
}
}
$container.append(append);
}
}, {
"name": "echo",
"type": "exec",
"mime": "application/x-sharedlib",
"help": "<span class=\"cmd\">echo</span>:\n\tWrite arguments to the standard output.\n\n\tDisplay the <span class=\"parameter\">ARGs</span>, separated by a single space character and\n\tfollowed by a newline, on the standard output.\n\n",
"func": function (argv) {
console.log(argv);
if (argv.help || argv.h) {
const cmd = self.builtIn.find(cmd => cmd.name === 'echo');
self.stdout(true, cmd.help);
return;
}
if (argv['_'] !== undefined) {
if (argv['_'][0].substring(0, 1) === "$") {
let str = argv['_'][0].slice(1);
console.log(str);
if (self.env.hasOwnProperty(str)) {
$container.append(self.env[str] + "\n\n");
return;
} else {
$container.append(eol);
return;
}
}
var str = argv._.join(" ");
return $container.append(str + "\n\n");
}
self.stdout(true, "bash: echo: Usage: echo [string]\n");
}
}];
let commandHistory = [];
let historyIndex = 0;
if (window.localStorage.getItem("cmdHistory") != null) {
commandHistory = JSON.parse(window.localStorage.getItem("cmdHistory"));
historyIndex = cmdHistory.length;
}
this.userCommands = [];
let commands = this.userCommands.concat(this.builtIn);
this.env = {
"HOME": "/home/demo",
"PWD": this.vfs._absolute_path(this.vfs.cwd),
"OLDPWD": null,
"USER": "demo",
"PROMPT": "$",
"HOSTNAME": location.protocol === "filesystem:" ? "localhost" : location.host,
"LANG": navigator.language,
"SHELL": "/bin/bash"
};
this.promptUser = async function (message, type, callback) {
//const inputField = document.createElement('input');
const $inputField = $("<input />");
$inputField[0].style.position = 'absolute';
$inputField[0].style.outline = 'none';
$inputField[0].style.border = 'none';
$inputField[0].style.backgroundColor = 'transparent';
$inputField[0].style.fontFamily = 'inherit';
$inputField[0].style.fontSize = '16px';
$inputField[0].style.fontVariant = 'small-caps';
$inputField[0].style.color = 'var(--fg)';
$inputField[0].style.marginLeft = '1em';
$inputField[0].style.marginTop = '-3px';
$inputField[0].style.letterSpacing = '2px';
if (message.length) {
$container.append(type === "confirm" ? message + ' [Y/n]: ' : message + ' ');
$container.append($inputField);
} else {
$container.append($inputField);
}
$container[0].onclick = function () {
$inputField[0].focus();
};
$inputField[0].onkeydown = function (e) {
if (e.code === 'ArrowUp' || e.code === 'ArrowRight' || e.code === 'ArrowLeft' || e.code === 'ArrowDown' || e.code === 'Tab') {
e.preventDefault();
}
};
$inputField[0].onkeyup = function (e) {
let inputValue = $inputField[0].value;
if (type === "confirm" && e.code !== 'Enter') {
if (e.code !== 'KeyY' && e.code !== 'KeyN') {
terminalObj._inputLine.textContent = inputField.value = '';
return;
}
}
if (e.code === "Enter") {
if (type === "confirm") {
if (!inputValue.length) {
return;
}
}
if (callback === undefined) {
$container[0].removeChild($inputField[0]);
$container.scrollTop($container[0].scrollHeight);
return new Promise(function (resolve) {
resolve(inputValue);
});
}
if (typeof (callback) === 'function') {
if (type === "confirm") {
if (inputValue.toUpperCase()[0] === 'Y') {
callback(true);
} else if (inputValue.toUpperCase()[0] === 'N') {
callback(false);
} else {
throw `promptInput_CONFIRM failed: Invalid input (${inputValue.toUpperCase()[0]}})`;
}
} else {
callback(inputValue);
}
$container[0].removeChild($inputField[0]);
$container.scrollTop($container.innerHeight());
}
}
};
$inputField[0].focus();
};
this.renderPrompt = function (kali = false) {
if (this.sudo === true) self.cursor = "#";
let cwd = self.vfs.cwd.name === "~" ? "/" : self.vfs._absolute_path(self.vfs.cwd);
if (self.kaliPrompt) {
terminal.stdout(true);
terminal.stdout(true, `<span class='info'>┏━(</span><span class='error'>${this.env.USER}☠ᴋᴀʟɪ</span><span class='info'>)━[</span>${cwd}<span class='info'>]</span>`);
terminal.stdout(false, `<span class='info'>┗</span><span class='error'>${self.cursor}</span> `);
} else {
terminal.stdout(true);
const $user = $("<span />").addClass("user").html(self.env.USER);
const $at = $("<span />").addClass("at").html("@");
const $host = $("<span />").addClass("host").html(self.env.HOSTNAME + " ");
const $path = $("<span />").addClass("path").html("[" + cwd + "] ");
const $cursor = $("<span />").addClass("cursor").html(self.cursor + " ");
$container.append($user, $at, $host, $path, $cursor);
}
};
this.processing = function (busy = "false") {
if (busy) {
this.busy = true;
} else {
this.busy = false;
}
};
this.secondaryCommand = function (on = "false") {
if (on) {
this.allowInput = false;
this.secondaryInstance = true;
$container.removeClass('blink');
} else {
this.allowInput = true;
this.secondaryInstance = false;
$container.addClass('blink');
}
};
this.registerCommand = function ({name, type, mime, func, help}) {
commands.push({name, type, mime, help, func});
self.userCommands.push({name, type, mime, help, func});
};
if (this.options.welcome) {
//$container.append(this.options.welcome + "\n\n");
}
this.clear = function () {
$container.html('');
};
function _parseCommand(stdin) {
return new Parser(stdin);
}
async function _processCommand() {
let isValid = false, argv, cmdFunc;
try {
argv = await _parseCommand(command);
} catch (e) {
self.stdout(true, `<span class="error">-fatal bash</span>: <span class="error">${e.message || 'An Error Occured while parsing the command string.'}</span>\n`);
return;
}
for (let i = 0; i < commands.length; i++) {
if (argv.command === commands[i].name) {
cmdFunc = commands[i].func;
await cmdFunc(argv);
isValid = true;
break;
}
}
if (!isValid) {
$container.append("-bash: <span class=\"cmd\">" + command + "</span>: <span class=\"error\">command not found</span>\n\n");
}
commandHistory.push(command);
historyIndex = commandHistory.length;
localStorage.setItem("commandHistory", JSON.stringify(commandHistory));
command = "";
$container.scrollTop($container[0].scrollHeight);
}
this.stdout = function (lineBreak = false, input = "", cls = "") {
$("<span />")
.addClass("stdout" + (cls !== undefined ? " " + cls : ""))
.html(input + (lineBreak ? "\n" : ""))
.appendTo($container);
$container.scrollTop($container.innerHeight());
};
this.clearCommand = function () {
if (command.length > 0) {
erase(command.length);
}
};
this.execCommand = async function (param) {
command = param;
await _processCommand();
};
this.appendCommand = function (str) {
$container.append(str);
command += str;
$container.scrollTop($container[0].scrollHeight);
};
this.wakeUp = function () {
if (this.busy !== true) {
let time;
window.onload = resetTime;
window.onclick = resetTime;
window.onkeydown = resetTime;
window.ontouchstart = resetTime;
window.onmousemove = resetTime;
window.onmousedown = resetTime;
window.addEventListener('scroll', resetTime, true);
const $clone = $container.clone();
function wakeUser() {
$container.hide();
$clone.html("").appendTo($terminal);
//$container.hide();
//$terminal.append($overlay);
const $type = $('<span />');
$type.addClass('typed-text');
$type.css("color", "#149414");
$clone.append($type);
const typedTextSpan = $type[0];
const textArray = [
"Wake up Neo...",
"The Matrix has you...",
"Follow the white rabbit.",
"Knock knock, Neo."
];
const typingDelay = 200;
const erasingDelay = 100;
const newTextDelay = 2000;
const loopLimit = 1;
let textArrayIndex = 0;
let charIndex = 0;
let loopCount = 0;
function type() {
if (charIndex < textArray[textArrayIndex].length) {
typedTextSpan.textContent += textArray[textArrayIndex].charAt(charIndex);
charIndex++;
setTimeout(type, typingDelay);
} else {
setTimeout(erase, newTextDelay);
}
}
function erase() {
if (charIndex > 0) {
typedTextSpan.textContent = textArray[textArrayIndex].substring(0, charIndex - 1);
charIndex--;
setTimeout(erase, erasingDelay);
} else {
textArrayIndex++;
if (textArrayIndex >= textArray.length) {
textArrayIndex = 0;
loopCount++;
if (loopCount >= loopLimit) {
let options = {
waitTime: 3500,
autoStart: false,
on: {
hideStart: function () {
return;
},
}
};
const $scsaver = $('<div />');
$scsaver.addClass('scsaver');
$scsaver.attr("id", "scsaver");
const $scinner = $('<div />');
$scinner.addClass('scsaver-inner');
$scsaver.append($scinner);
$clone.append($scsaver);
const scsaver = new Scsaver('#scsaver', options);
scsaver.disabled();
const $main = $("<main />");
$scinner.append($main);
for (let i = 0; i < 50; ++i) {
new Raindrop({container: $main[0], row: 50});
}
scsaver.enabled();
return;
}
}
setTimeout(type, typingDelay + 1100);
}
}
setTimeout(type, newTextDelay + 250);
}
function resetTime() {
clearTimeout(time);
time = setTimeout(wakeUser, 1000 * 100);
$clone.remove();
$container.show();
return;
}
}
};
function erase(n) {
command = command.slice(0, -n);
$container.html($container.html().slice(0, -n));
}
async function paste() {
if (copiedText !== null) {
self.appendCommand(copiedText);
} else {
const $input = $("<input />");
const text = await navigator.clipboard.readText();
$input.val(text);
const value = $input.val();
self.appendCommand(value);
}
}
$terminal.find(".container").on("contextmenu", async function (e) {
e.preventDefault();
await paste();
});
document.addEventListener('paste', async (e) => {
e.preventDefault();
const text = await navigator.clipboard.readText();
self.appendCommand(text);
});
$container.on("mouseup", async function () {
if (document.getSelection) {
copiedText = document.getSelection().toString();
if (navigator.clipboard) {
await navigator.clipboard.writeText(copiedText);
} else {
document.execCommand("copy");
}
} else {
if (document.selection.createRange) {
copiedText = document.selection.createRange();
if (navigator.clipboard) {
await navigator.clipboard.writeText(copiedText);
} else {
document.execCommand("copy");
}
}
}
});
$(document).on("keydown", function (e) {
if (!self.allowInput) {
return;
}
e = e || window.event;
let keyCode = typeof e.which === "number" ? e.which : e.keyCode;
// BACKSPACE
if (keyCode === 8 && e.target.tagName !== "input" && e.target.tagName !== "textarea") {
e.preventDefault();
if (command !== "") {
erase(1);
}
}
// UP or DOWN
if (keyCode === 38 || keyCode === 40) {
e.preventDefault();
$container.scrollTop($container.innerHeight());
// Move up or down the history
if (keyCode === 38) {
// UP
historyIndex--;
if (historyIndex < 0) {
historyIndex++;
}
} else if (keyCode === 40) {
// DOWN
historyIndex++;
if (historyIndex > commandHistory.length - 1) {
historyIndex--;
}
}
// Get command
let cmd = commandHistory[historyIndex];
localStorage.setItem("commandHistory", JSON.stringify(commandHistory));
if (cmd !== undefined) {
self.clearCommand();
self.appendCommand(cmd);
}
}
});
$(document).on("keypress", async function (e) {
if (!self.allowInput) {
return;
}
e = e || window.event;
let keyCode = typeof e.which === "number" ? e.which : e.keyCode;
switch (keyCode) {
case 13: // ENTER
self.stdout(true);
await _processCommand();
if (!self.secondaryInstance) {
self.renderPrompt();
}
break;
default:
$container.scrollTop($container.innerHeight());
self.appendCommand(String.fromCharCode(keyCode));
}
});
}
};
let date = new Date().toString();
date = date.substring(0, date.indexOf("GMT") - 10);
const terminal = new Termeditor("terminal");
terminal.vfs.initStructure(DEFAULT_FS, null);
terminal.vfs.cwd = terminal.vfs.tree.root;
terminal.vfs.mkdir("usr");
terminal.vfs.cd("usr");
terminal.vfs.mkdir("bin");
terminal.vfs.cd("bin");
terminal.builtIn.sort((a, b) => {
const A = a.name.toUpperCase();
const B = b.name.toUpperCase();
if (A < B) {
return -1;
}
if (A > B) {
return 1;
}
return 0;
});
terminal.builtIn.forEach(function (cmd) {
let exec = {
"name": cmd.name,
"type": cmd.type,
"link": cmd.link,
"permissions": "rwxr-xr-x",
"group": "root",
"user": "root",
"size": cmd.func.toString().length,
"modified": terminal.vfs.getDate(),
"mime": cmd.mime,
"contents": cmd.func.toString()
};
terminal.vfs.tree.insert(cmd, terminal.vfs._resolve_path("/bin"), exec);
});
terminal.vfs.cd("/home/demo");
terminal.registerCommand({
"name": "fortune",
"type": "script",
"mime": "application/javascript",
"help": "<span class=\"cmd\">fortune</span>:\nGet a fortune cookie quote.\n\nGet one virtual fortune cookie and a random quote along with it.\n\nYour fortune foretold as told by a fortune cookie.\n\n",
"func": function (argv) {
if (argv.help || argv.h) {
const cmd = terminal.userCommands.find(cmd => cmd.name === 'fortune');
terminal.stdout(true, cmd.help);
return;
}
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://cdn.rawgit.com/bmc/fortunes/master/fortunes', false);
xhr.send(null);
if (xhr.status === 200) {
let fortunes = xhr.responseText.split("%");
let fortune = fortunes[util.rand(fortunes.length)].trim();
$(".container").append("<strong>Your fortune foretold as told by a fortune cookie:</strong>\n");
$(".container").append(" 🥠: " + fortune + "\n\n");
} else {
$(".container").append("bash: fortune: An error occured while grabbing your cookie..\n\n");
}
}
});
terminal.registerCommand({
"name": "yomomma",
"type": "script",
"mime": "application/javascript",
"help": "<span class=\"cmd\">yomomma</span>:\nInsults your momma.\n\nGet one insult towards your momma.\n\n",
"func": function (argv) {
if (argv.help || argv.h) {
const cmd = terminal.userCommands.find(cmd => cmd.name === 'yomomma');
terminal.stdout(true, cmd.help);
return;
}
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://raw.githubusercontent.com/beanboi7/yomomma-apiv2/master/jokes.json', false);
xhr.send(null);
if (xhr.status === 200) {
let jokes = xhr.responseText.split("\n");
let joke = jokes[util.rand(jokes.length)].trim();
terminal.stdout(true, util.wordBreak(joke));
terminal.stdout(true);
} else {
terminal.stdout(true, "bash: fortune: An error occured while trying to insult yo momma..\n\n");
}
}
});
terminal.registerCommand({
"name": "chuck",
"type": "script",
"mime": "application/javascript",
"help": "<span class=\"cmd\">chuck</span>:\nGet a Chuck Norris joke.\n\nDisplay a random Chuck Norris fact or joke.\n\n",
"func": async function (argv) {
console.log(argv);
if (argv.help || argv.h) {
const cmd = terminal.userCommands.find(cmd => cmd.name === 'chuck');
terminal.stdout(true, cmd.help);
return;
}
let url = "https://api.chucknorris.io/jokes/random";
await util.fetch(url, {mode: 'cors'}).then(data => {
terminal.stdout(true, util.wordBreak(data.value) + "\n");
}).catch(error => {
console.log(error);
terminal.stdout(true, "bash: chuck: The only time Chuck Norris was wrong was when he thought he\nhad made a mistake.\n");
});
}
});
terminal.registerCommand({
"name": "agify",
"type": "script",
"mime": "application/javascript",
"help": "<span class=\"cmd\">agify</span>: [<span class=\"user\">name</span>]\nPredicte the age of a person given their name.\n\nAgify.io predicts the age of a person given their name.\n\n",
"func": async function (argv) {
console.log(argv);
if (argv.help || argv.h) {
const cmd = terminal.userCommands.find(cmd => cmd.name === 'agify');
terminal.stdout(true, cmd.help);
return;
}
if (argv._.length !== 0) {
const name = argv._;
let url = `https://api.agify.io?name=${name}`;
await util.fetch(url, {mode: 'cors'}).then(data => {
terminal.stdout(true, `${data.name} is aproximately ${data.age} years old..`);
terminal.stdout(true);
}).catch(error => {
console.log(error);
terminal.stdout(true, "bash: agify: ${error}");
});
}
}
});
terminal.registerCommand({
"name": "verse",
"type": "script",
"mime": "application/javascript",
"help": "<span class=\"cmd\">verse</span>:\nGet a bible verse.\n\nDisplay a random bible verse.\n\n",
"func": async function (argv) {
console.log(argv);
if (argv.help || argv.h) {
const cmd = terminal.userCommands.find(cmd => cmd.name === 'verse');
terminal.stdout(true, cmd.help);
return;
}
const VERSES = [
`JER.29.11`,
`PSA.23`,
`1COR.4.4-8`,
`PHP.4.13`,
`JHN.3.16`,
`ROM.8.28`,
`ISA.41.10`,
`PSA.46.1`,
`GAL.5.22-23`,
`HEB.11.1`,
`2TI.1.7`,
`1COR.10.13`,
`PRO.22.6`,
`ISA.40.31`,
`JOS.1.9`,
`HEB.12.2`,
`MAT.11.28`,
`ROM.10.9-10`,
`PHP.2.3-4`,
`MAT.5.43-44`,
];
const verseIndex = Math.floor(Math.random() * VERSES.length);
const verseID = VERSES[verseIndex];
//const key = util.b64.de(`ZmIzNmRjNzQyMGNhMTVhMzg0OGZjNGQ5OTJjNmE0YmYK`);
getResults(verseID).then((data) => {
const passage = data.passages[0];
terminal.stdout(true);
terminal.stdout(true, util.wordBreak(passage.referance));
terminal.stdout(true, util.wordBreak(passage.content));
});
function getResults(verseID) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.withCredentials = false;
xhr.addEventListener(`readystatechange`, function () {
if (this.readyState === this.DONE) {
const {data, meta} = JSON.parse(this.responseText);
_BAPI.t(meta.fumsId);
resolve(data);
}
});
xhr.open(
`GET`,
`https://api.scripture.api.bible/v1/bibles/61fd76eafa1577c2-02/search?query=${verseID}`
);
xhr.setRequestHeader(`api-key`, 'fb36dc7420ca15a3848fc4d992c6a4bf');
xhr.onerror = () => reject(xhr.statusText);
xhr.send();
});
}
/*let url = `https://api.scripture.api.bible/v1/bibles/61fd76eafa1577c2-02/search?query=${verseID}`;
const fetchVerse = async (link) => {
const response = await fetch(link, {
mode: 'cors',
headers: {
'api-key': key,
}
});
if (response.ok) {
const verse = await response.json();
return Promise.resolve(verse);
} else {
return Promise.reject("Opps!!");
}
};
await fetchVerse(url).then(data => {
const passage = data.passages[0];
terminal.stdout(true);
terminal.stdout(true, util.wordBreak(passage.referance));
terminal.stdout(true, util.wordBreak(passage.content));
}).catch(error => {
console.log(error);
terminal.stdout(true, "bash: chuck: The only time Chuck Norris was wrong was when he thought he\nhad made a mistake.\n");
}); */
}
});
terminal.registerCommand({
"name": "kali",
"type": "script",
"mime": "application/javascript",
"help": "<span class=\"cmd\">kali</span>:\nStart Kali Linux.\n\nBoot into a Kali Linux Live session.\n\n",
"func": async function (argv) {
if (argv.help || argv.h) {
const cmd = terminal.userCommands.find(cmd => cmd.name === 'kali');
terminal.stdout(true, cmd.help);
return;
}
if (argv._.length === 0) {
terminal.processing(true);
let randIP = () => {return `${util.rand(255)}.${util.rand(255)}.${util.rand(255)}.${util.rand(255)}`;};
terminal.stdout(true, "Booting Kali. This may take a few minutes...");
terminal.container.scrollTop(terminal.container.innerHeight());
await util.sleep(2500);
terminal.stdout(true, "root@kali.org:-$ telnet -l root 172.64.33.209");
terminal.container.scrollTop(terminal.container.innerHeight());
await util.sleep(1500);
terminal.stdout(true, "<span class='warn'>WARNING: Network connections are about to go down.</span>\n\tWill try to re-establish a connection on disconnect.\n");
terminal.container.scrollTop(terminal.container.innerHeight());
await util.sleep(3500);
terminal.stdout(true, "Kali Linux 2023.3 (Kernel 6.3.0, Xfce 4.18.4)");
terminal.container.scrollTop(terminal.container.innerHeight());
terminal.stdout(true, "Trying " + randIP() + "");
terminal.container.scrollTop(terminal.container.innerHeight());
await util.sleep(util.rand(1500));
terminal.stdout(true, "Connected to localhost");
terminal.container.scrollTop(terminal.container.innerHeight());
await util.sleep(util.rand(1500));
terminal.stdout(true, "login: root");
terminal.container.scrollTop(terminal.container.innerHeight());
await util.sleep(util.rand(1500));
terminal.stdout(true, "password: ********");
terminal.container.scrollTop(terminal.container.innerHeight());
await util.sleep(util.rand(1500));
terminal.stdout(true, "Last login: Tue Aug 10 16:51:20 from hacksploit");
terminal.container.scrollTop(terminal.container.innerHeight());
await util.sleep(util.rand(1500));
terminal.stdout(true, "Welcome to localhost!");
terminal.container.scrollTop(terminal.container.innerHeight());
await util.sleep(util.rand(1500));
terminal.stdout(true, "Tunnel adapter Local Area Connection* 9:");
terminal.container.scrollTop(terminal.container.innerHeight());
await util.sleep(util.rand(1500));
terminal.stdout(true, " Media State . . . . . . . . . . . : Media disconnected");
terminal.container.scrollTop(terminal.container.innerHeight());
await util.sleep(util.rand(1500));
terminal.stdout(true, " Connection-specific DNS Suffix . :");
terminal.container.scrollTop(terminal.container.innerHeight());
await util.sleep(util.rand(1500));
terminal.stdout(true, " Description . . . . . . . . . . . : Microsoft Teredo Tunneling Adapter");
terminal.container.scrollTop(terminal.container.innerHeight());
await util.sleep(util.rand(1500));
terminal.stdout(true, " MAC Address . . . . . . . . . . . : 0E:CC:73:B6:96:8F");
terminal.container.scrollTop(terminal.container.innerHeight());
await util.sleep(util.rand(1500));
terminal.stdout(true, " DHCP Enabled. . . . . . . . . . . : No");
terminal.container.scrollTop(terminal.container.innerHeight());
await util.sleep(util.rand(1500));
terminal.stdout(true, " Autoconfiguration Enabled . . . . : Yes");
terminal.container.scrollTop(terminal.container.innerHeight());
await util.sleep(3000);
terminal.container.html("");
terminal.stdout(true, "   ..............");
terminal.stdout(true, "    ..,;:ccc,.");
terminal.stdout(true, "    ......''';lxO.");
terminal.stdout(true, "   .....''''..........,:ld;");
terminal.stdout(true, "    .';;;:::;,,.x,");
terminal.stdout(true, "    ..'''. 0Xxoc:,. ...");
terminal.stdout(true, "    .... ,ONkc;,;cokOdc',.");
terminal.stdout(true, "    . OMo ':ddo.");
terminal.stdout(true, "    dMc :OO;");
terminal.stdout(true, "    0M. .:o.");
terminal.stdout(true, "    ;Wd");
terminal.stdout(true, "    ;XO,");
terminal.stdout(true, "    ,d0Odlc;,..");
terminal.stdout(true, "    ..',;:cdOOd::,.");
terminal.stdout(true, "    .:d;.':;.");
terminal.stdout(true, "    'd, .'");
terminal.stdout(true, "    ;l ..");
terminal.stdout(true, "    .o");
terminal.stdout(true, "    c");
terminal.stdout(true, "    .'");
terminal.stdout(true, "    .");
const makeConnection = async function() {
let connection = await new Typed('.connection', {
strings : [$('.connection').text(),"Matching modules...","exploit/windows/smb/ms06_070_wkssvc | MS06-070 Microsoft Workstation Service NetpManageIPCConnect Overflow","Starting connection to (https://sololearn.com/courses/databases)","Fetching information... 12%","Fetching information... 23%","Fetching information... 31%","Fetching information... 45%","Fetching information... 51%","Fetching information... 67%","Fetching information... 81%","Fetching information... 93%","Fetching information... 99%","Fetching information... 100%","Data successfully stored in /home/demo",""],
stringsElement: null,
backSpeed: 0,
smartBackspace: true,
typeSpeed: 40,
showCursor: false,
cursorChar: '█',
autoInsertCss: true,
onComplete: async () => {
terminal.container.scrollTop(terminal.container.innerHeight());
await util.sleep(1500);
//terminal.stdout(true, "<span class='info'>┏━(</span><span class='error'>ʀᴏᴏᴛ☠ᴋᴀʟɪ</span><span class='info'>)━[</span>~<span class='info'>]</span>");
//terminal.stdout(true, "<span class='info'>┗</span><span class='error'>#</span>");
terminal.kaliPrompt = true;
terminal.processing(false);
}
})
}
$("<span />").addClass("connection").appendTo(terminal.container);
await makeConnection();
}
return;
}
});
terminal.registerCommand({
"name": "hacksploit",
"type": "script",
"mime": "application/javascript",
"help": "<span class=\"cmd\">hacksploit</span>:\n\tLaunch the Hacksploit framework\n\n\tDepending on the target, this command will scan penetration frameworks\n\tto download applicable exploits, payloads, and other various modules.\n\n\tIt will check the host for vulnerabilities, run the modules against the\n\ttarget, execute the payload(s) upon connection, then exports any hash\n\tand/or password dumps to the local filesystem.\n\n\t<span class=\"info\">ATTN: Just a simulation. This is a fake command..</span>\n\n",
"func": async function (argv) {
console.log(argv);
if (argv.help || argv.h) {
const cmd = terminal.userCommands.find(cmd => cmd.name === 'hacksploit');
terminal.stdout(true, cmd.help);
return;
}
if (argv._.length === 0) {
terminal.secondaryCommand(true);
terminal.processing(true);
terminal.stdout(true, "Launching Hacksploit..");
await util.sleep(3500);
const loading = [
'Now loading',
'Please wait',
'Now loading..',
'Please wait..',
'Now loading...',
'Please wait...'
];
terminal.clear();
terminal.stdout(true);
terminal.stdout(true);
terminal.stdout(true);
terminal.stdout(true, "   ⠀⠀⠀▄ .▄ ▄▄▄· ▄▄· ▄ •▄ .▄▄ · ▄▄▄·▄▄▌ ▪ ▄▄▄▄▄▄");
terminal.stdout(true, "   ⠀⠀██▪▐█▐█ ▀█ ▐█ ▌▪█▌▄▌▪▐█ ▀. ▐█ ▄███• ▄█▀▄ ██ ▀•██ ▀");
terminal.stdout(true, "   ⠀⠀██▀▀█▄█▀▀█ ██ ▄▄▐▀▀▄·▄▀▀▀█▄ ██▀·██ ▪ ▐█▌.▐▌▐█· ▐█.▪");
terminal.stdout(true, "   ⠀⠀██▌▐▀▐█▪ ▐▌▐███▌▐█.█▌▐█▄▪▐█▐█▪·•▐█▌ ▄▐█▌.▐▌▐█▌ ▐█▌·");
terminal.stdout(true, "   ⠀⠀▀▀▀ · ▀ ▀ ·▀▀▀ ·▀ ▀ ▀▀▀▀ .▀ .▀▀▀ ▀█▄▀▪▀▀▀ ▀▀▀ ");
terminal.stdout(true, "   ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀by daemon.devin");
terminal.stdout(true, "   ⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠞⠀⠀⠀⠀⠀⠀⠱⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀");
terminal.stdout(true, "   ⠀⠀⠀⠀⠀⠀⠀⢀⠏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠹⡀⠀⠀⠀⠀⠀⠀⠀⠀");
terminal.stdout(true, "   ⠀⠀⠀⠀⠀⠀⠀⡜⠀⠀⠀⠀⠀⣀⣀⠀⠀⠀⠀⠀⢣⠀⠀⠀⠀⠀⠀⠀⠀");
terminal.stdout(true, "   ⠀⠀⠀⠀⠀⠀⠀⡇⠀⣠⠔⠋⠉⣩⣍⠉⠙⠢⣄⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀");
terminal.stdout(true, "   ⠀⠀⠀⠀⠀⠀⠀⢧⡜⢏⠓⠒⠚⠁⠈⠑⠒⠚⣹⢳⡸⠀⠀⠀⠀⠀⠀⠀⠀<span class='loading'></span>");
terminal.stdout(true, "   ⠀⠀⠀⠀⠀⠀⠀⠘⣆⠸⡄⠀⠀⠀⠀⠀⠀⢠⠇⣰⠃⠀⠀⠀⠀⠀⠀⠀⠀");
terminal.stdout(true, "   ⠀⠀⠀⠀⠀⢀⡴⠚⠉⢣⡙⢦⡀⠀⠀⢀⡰⢋⡜⠉⠓⠦⣀⠀⠀⠀⠀⠀⠀");
terminal.stdout(true, "   ⠀⠀⠀⠀⡴⠁⢀⣀⣀⣀⣙⣦⣉⣉⣋⣉⣴⣋⣀⣀⣀⡀⠈⢧⠀⠀⠀⠀⠀");
terminal.stdout(true, "   ⠀⠀⠀⡸⠁⠀⢸⠀⠀⠀⠀⢀⣔⡛⠛⡲⡀⠀⠀⠀⠀⡇⠀⠈⢇⠀⠀⠀⠀");
terminal.stdout(true, "   ⠀⠀⢠⠇⠀⠀⠸⡀⠀⠀⠀⠸⣼⠽⠯⢧⠇⠀⠀⠀⠀⡇⠀⠀⠘⡆⠀⠀⠀");
terminal.stdout(true, "   ⠀⠀⣸⠀⠀⠀⠀⡇⠀⠀⠀⠳⢼⡦⢴⡯⠞⠀⠀⠀⢰⠀⠀⠀⠀⢧⠀⠀⠀");
terminal.stdout(true, "   ⠀⠀⢻⠀⠀⠀⠀⡇⠀⠀⠀⢀⡤⠚⠛⢦⣀⠀⠀⠀⢸⠀⠀⠀⠀⡼⠀⠀⠀");
terminal.stdout(true, "   ⠀⠀⠈⠳⠤⠤⣖⣓⣒⣒⣒⣓⣒⣒⣒⣒⣚⣒⣒⣒⣚⣲⠤⠤⠖⠁⠀⠀⠀");
terminal.stdout(true, "\n");
await util.sleep(1500);
const l = document.querySelector('.loading');
const fx = new TextScramble(l);
let counter = 0;
const next = () => {
fx.setText(loading[counter]).then(() => {
setTimeout(next, 800);
});
counter = (counter + 1) % loading.length;
};
next();
await util.sleep(10000);
terminal.processing(false);
terminal.container.html("");
terminal.stdout(true, "₩ɆⱠ₵Ø₥Ɇ ₮Ø Ⱨ₳₵₭₴₱ⱠØł₮");
terminal.stdout(true);
terminal.stdout(true, "ʜᴀᴄᴋꜱᴩʟᴏɪᴛ ʟᴏɢɪɴ");
let userName, userIP;
await terminal.promptUser("ᴀʟɪᴀꜱ »", "input", async function (input) {
userName = input;
await util.sleep(1000);
let randIP = () => {return `${util.rand(255)}.${util.rand(255)}.${util.rand(255)}.${util.rand(255)}`;};
terminal.container.html("");
try {
const response = await fetch('https://api64.ipify.org?format=json');
const data = await response.json();
userIP = data.ip;
} catch (error) {
console.error('Failed to retrieve client IP:', error);
userIP = randIP();
}
terminal.stdout(true, "Welcome " + userName + "");
terminal.container.scrollTop(terminal.container.innerHeight());
await util.sleep(2500);
terminal.stdout(true, "<span class='info'>\nLast logged in from " + randIP() + "</span>\nCurrently logged in from: <span class='success'>" + userIP + "</span>\n");
terminal.container.scrollTop(terminal.container.innerHeight());
await util.sleep(3000);
terminal.stdout(true, "Enter a <span class='path'>hostname</span> or <span class='path'>ip address</span> to exploit:");
await terminal.promptUser("ʜᴀᴄᴋꜱᴩʟᴏɪᴛ »", "input", async function (input) {
function validInput(input) {
return util.isHostname(input) || util.isIPAddress(input);
}
if (validInput(input)) {
let stdin = `hacksploit ${input} --hack`;
await terminal.execCommand(stdin);
} else {
terminal.stdout(true, "<span class='error'>\n\nYou don't belong here..</span>\nBack from whence thou came!\n");
await util.sleep(3000);
terminal.secondaryCommand(false);
terminal.container.html("");
terminal.renderPrompt();
return;
}
});
});
}
if (argv._.length > 0 && argv.hack) {
terminal.processing(true);
$("body").data("");
let $hackData;
const tools = "hydra,hashcat,john,apktool,medusa,aircrack-ng,wifite,metasploit,redeye,wireshark,binwalk,fcrackzip,wifiphisher,sslscan,reaver".split(",");
let tool = {phase: 0, d: []};
let j, x, t, d, p;
terminal.stdout(true);
terminal.stdout(true, "Downloading exploits.. please wait!\n");
for (let i = 0; i < util.rand(tools.length); i++) {
x = tools.splice(util.rand(tools.length - 1), 1)[0];
const $progress = document.createElement("span");
$progress.className = "progress" + x;
$progress.setAttribute("data-count", i);
terminal.container[0].append($progress);
terminal.stdout(true);
tool.d[i] = {n: x, i: util.history.index - 1, p: 0};
}
$("body").data(tool);
let stdin = `hacksploit ${argv._} -download`;
await terminal.execCommand(stdin);
}
if (argv._.length > 0 && argv.download) {
$hackData = $("body").data();
if (!navigator.onLine) {
terminal.stdout(true, "bash: hack: No internet connection...");
return;
}
if ($hackData.phase === 0) {
setTimeout(async function () {
let i = 0;
await $hackData.d.forEach(async function (e) {
if (e.p !== 100) {
e.p += util.rand(e.n.length);
if (e.p > 100) {
e.p = 100;
i++;
}
//terminal.stdout(true, "Import: '" + e.n + "' -> " + e.p + "%");
await util.showProgress(i, e.p, 100, "Import: " + e.n, "");
} else {
i++;
}
});
$("body").data($hackData);
if (i === $hackData.d.length) {
$hackData.phase = 1;
$hackData.d = [' |0', 'Connection to \'' + argv._[0] + '\' (' + util.rand(255) + '.' + util.rand(255) + '.' + util.rand(255) + '.' + util.rand(255) + ')|' + (util.rand(5000) + 500)];
$hackData.d = $hackData.d.concat(util.newArray(util.rand(10) + 5, '.|20'));
$hackData.d.push(' |100');
for (let j = 0; j < util.rand(25) + 2; j++) {
let y = util.rand(30);
for (let x = 0; x < y; x++) {
$hackData.d.push((y * (x + 1)) + ' / ' + (y * y) + ' bytes|' + (util.rand(10) + 20));
}
$hackData.d.push(' |120');
}
for (let j = 0; j < util.rand(2000) + 500; j++) {
$hackData.d.push(util.createName(Math.floor(innerWidth / 8.44) - 1) + '|5');
}
}
$("body").data($hackData);
let stdin = `hacksploit ${argv._} -download`;
await terminal.execCommand(stdin);
}, util.rand(69) + 100);
} else if ($hackData.phase === 1) {
$hackData = $("body").data();
if ($hackData.d.length !== 0) {
let l = $hackData.d.shift().split('|');
terminal.container.append(l[0] + "\n");
setTimeout(async function () {
$("body").data($hackData);
let stdin = `hacksploit ${argv._} -download`;
await terminal.execCommand(stdin);
}, parseInt(l[1]));
return;
} else {
$hackData.phase = 2;
terminal.stdout(true);
terminal.stdout(true, "ACCESS GRANTED!", "success");
terminal.stdout(true, "<strong>Server Information:</strong>", "warn");
terminal.stdout(true, " Host: " + argv._ + " ");
terminal.stdout(true, " Database: <span class=\"info\">phpMyAdmin v1.52.1a</span>");
terminal.stdout(true, " Database Login: <span class=\"user\">root</span>@<span class=\"host\">" + util.rand(255) + "." + util.rand(255) + "." + util.rand(255) + "." + util.rand(255) + "</span>");
terminal.stdout(true);
terminal.processing(false);
terminal.renderPrompt();
terminal.secondaryCommand(false);
$("body").data($hackData);
return;
}
}
}
}
});
terminal.registerCommand({
"name": "rps",
"type": "script",
"mime": "application/javascript",
"help": "<span class=\"cmd\">rps</span>: [<span class=\"parameters\">rock|paper|scissors</span>]\nRock, Paper, Scissors.\n\nPlay against the computer. Choose between rock, paper, or scissors.\n\nRules:\n\tRock beats scissors\n\tPaper beats rock\n\tScissors beats paper\n\n",
"func": async function (argv) {
console.log(argv);
if (argv.help || argv.h) {
const cmd = terminal.userCommands.find(cmd => cmd.name === 'rps');
terminal.stdout(true, cmd.help);
return;
}
const rps = ['rock', 'paper', 'scissors'];
if (argv._[0] === rps[0] || argv._[0] === rps[1] || argv._[0] === rps[2]) {
let playerInput = argv._[0];
let computerInput = rps[Math.floor(Math.random() * 3)];
const checkWinner = (player1, player2) => {
if (player1 === player2) return 0;
if (player1 === rps[0]) {
return (player2 === rps[2] ? 1 : -1);
} else if (player1 === rps[1]) {
return (player2 === rps[0] ? 1 : -1);
}
return (player2 === rps[1] ? 1 : -1);
};
let result = checkWinner(playerInput, computerInput);
terminal.stdout(false, "You: ");
terminal.stdout(true, playerInput, "parameter");
terminal.stdout(false, "Computer: ");
terminal.stdout(true, computerInput, "parameter");
terminal.stdout(true);
if (result === -1) {
terminal.stdout(true, "You lost!", "error");
} else if (result === 0) {
terminal.stdout(true, "You tied with the computer!", "info");
} else {
terminal.stdout(true, "You win!", "success");
}
terminal.stdout(true);
return;
} else {
terminal.stdout(true, "bash: rps: Usage rps [rock|paper|scissors]");
terminal.stdout(true);
}
}
});
terminal.registerCommand({
"name": "npm",
"type": "script",
"mime": "application/javascript",
"help": "<span class=\"cmd\">npm</span>: [<span class=\"parameter\">package</span>] [<span class=\"parameter\">--readme</span>]\n\tGet information on a npm package\n\n\tSearch the npm public database registry for npm packages matching the\n\tparameter <span class=\"parameter\">package</span>.\n\n\tOptions:\n\t -r, --readme\tdisplay the package's markdown parsed readme file\n\n",
"func": async function (argv) {
console.log(argv);
if (argv.help || argv.h) {
const cmd = terminal.userCommands.find(cmd => cmd.name === 'npm');
terminal.stdout(true, cmd.help);
return;
}
const formatDate = (input) => {return new Date(input).toLocaleDateString();};
if (argv._.length !== 0) {
const packageName = argv._[0];
terminal.stdout(true, `Searching ${packageName} in npm's registry...`);
const data = await fetch(`https://registry.npmjs.org/${encodeURIComponent(packageName)}`).then(r => r.json());
if (data.error) {
terminal.stdout(true, `There was an error while trying to search npm's registry.`);
terminal.stdout(true, `Error: ${data.error}`, "error");
return;
}
terminal.stdout(true);
terminal.stdout(false, "<strong>Package:</strong> ");
terminal.stdout(true, `${data.name}`, "success");
terminal.stdout(false, "<strong>Author:</strong> ");
terminal.stdout(false, `${data.author.name}`);
if (data.author.url) {
terminal.stdout(true, ` [<a href='${data.author.url}' target'_blank'>Link</a>]`);
} else {
terminal.stdout(true);
}
terminal.stdout(false, "<strong>Version:</strong> ");
terminal.stdout(true, data["dist-tags"].latest, "info");
if (data.time.created) {
terminal.stdout(false, "<strong>Created:</strong> ");
terminal.stdout(true, formatDate(data.time.created));
}
terminal.stdout(true);
if (data.homepage) {
terminal.stdout(false, "<strong>Homepage:</strong> ");
terminal.stdout(true, `<a href='${data.homepage}' target'_blank'>Link</a>`);
}
if (data.license) {
terminal.stdout(false, "<strong>License:</strong> ");
terminal.stdout(true, data.license, "info");
}
if (data.time.modified) {
terminal.stdout(false, "<strong>Last Updated:</strong> ");
terminal.stdout(true, formatDate(data.time.modified));
}
if (data.description) {
terminal.stdout(true, "<strong>Package Description:</strong> ");
terminal.stdout(true, util.wordBreak(data.description), "info");
}
terminal.stdout(true);
if (argv.readme || argv.r) {
if (data.readme) {
if (data.readmeFilename) {
terminal.stdout(true, `<strong>README:</strong> ${data.readmeFilename}`);
terminal.stdout(true, util.wordBreak(util.MDParser(data.readme)));
} else {
terminal.stdout(true, "<strong>README:</strong>");
terminal.stdout(true, util.wordBreak(util.MDParser(data.readme)));
}
} else {
terminal.stdout(true, "No README was provided.", "warn");
}
terminal.stdout(true);
}
} else {
terminal.stdout(true, "bash: npm: Usage: npm [package] [--readme]");
terminal.stdout(true);
}
}
});
terminal.registerCommand({
"name": "whois",
"type": "script",
"mime": "application/javascript",
"help": "<span class=\"cmd\">whois</span>: [<span class=\"parameter\">domain</span>]\n\tQuery WHOIS information on a domain.\n\n\tProvides comprehensive WHOIS data such as creation date, expiration date,\n\tdomain age, contact information of the registrant, email address,\n\tnameservers, etc.\n\n",
"func": async function (argv) {
console.log(argv);
if (argv.help || argv.h) {
const cmd = terminal.userCommands.find(cmd => cmd.name === 'whois');
terminal.stdout(true, cmd.help);
return;
}
const key = util.b64.de(`RDg3ODgwNjg3OEM4MDZEQzYwREY4RjA1NkU2NTA5MjAK`);
if (argv._[0] !== undefined) {
const domain = argv._[0];
//let data = null;
terminal.stdout(true, `Querying IP2Location.io with ${domain}...`);
let response = await fetch(`https://api.ip2whois.com/v2?format=json&key=${key}&domain=${encodeURIComponent(domain)}`, {
method: "GET",
headers: {
"accept": "application/json",
"accept-language": "en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7"
},
});
const data = await response.json();
/*if (data.error) {
terminal.stdout(true, `There was an error while trying to obtain domain information for: ${domain}`);
terminal.stdout(true, `ERROR: ${data.error.error_code}`, "warn")
terminal.stdout(true, `${data.error.error_message}`, "error");
return;
}*/
terminal.stdout(true);
terminal.stdout(false, "<strong>Domain:</strong> ");
terminal.stdout(true, `${data.domain}`, "success");
terminal.stdout(false, "<strong>Status:</strong> ");
terminal.stdout(true, `${data.status}`, "warn");
terminal.stdout(false, "<strong>Created:</strong> ");
terminal.stdout(true, data.create_date, "info");
terminal.stdout(false, "<strong>Updated:</strong> ");
terminal.stdout(true, data.update_date, "info");
terminal.stdout(false, "<strong>Expires:</strong> ");
terminal.stdout(true, data.expire_date, "info");
terminal.stdout(true);
terminal.stdout(false, "<strong>WHOIS Server:</strong> ");
terminal.stdout(true, data.whois_server);
terminal.stdout(true);
terminal.stdout(true, "<strong>Registrar:</strong>", "success");
terminal.stdout(true, "\tRegistrar: " + data.registrar.name);
terminal.stdout(true, "\tHomepage: " + data.registrar.url);
terminal.stdout(true, "\tName: " + data.registrant.name);
terminal.stdout(true, "\tOrganization: " + data.registrar.organization);
terminal.stdout(true, "\tCountry: " + data.registrant.country);
terminal.stdout(true, "\tEmail: " + data.registrant.email);
terminal.stdout(true);
terminal.stdout(true, "<strong>Admin:</strong>", "success");
terminal.stdout(true, "\tName: " + data.admin.name);
terminal.stdout(true, "\tOrganization: " + data.admin.organization);
terminal.stdout(true, "\tCountry: " + data.admin.country);
terminal.stdout(true, "\tEmail: " + data.admin.email);
terminal.stdout(true);
terminal.stdout(true, "Name Servers: ");
terminal.stdout(true, data.nameservers, "info");
terminal.stdout(true);
} else {
terminal.stdout(true, "bash: npm: Usage: npm [package] [--readme]");
terminal.stdout(true);
}
}
});
terminal.registerCommand({
"name": "imdb",
"type": "script",
"mime": "application/javascript",
"help": "<span class=\"cmd\">npm</span>: [<span class=\"parameter\">package</span>] [<span class=\"parameter\">--readme</span>]\n\tGet information on a npm package\n\n\tSearch the npm public database registry for npm packages matching the\n\tparameter <span class=\"parameter\">package</span>.\n\n\tOptions:\n\t -r, --readme\tdisplay the package's markdown parsed readme file\n\n",
"func": async function (argv) {
console.log(argv);
if (argv.help || argv.h) {
const cmd = terminal.userCommands.find(cmd => cmd.name === 'imdb');
terminal.stdout(true, cmd.help);
return;
}
const key = util.b64.de(`NmRkM2MwMjI=`);
if (argv._.length !== 0) {
const movieName = argv._.join(' ');
let url = `https://omdbapi.com/?apikey=${key}&t=${movieName}`;
terminal.stdout(true, `Searching for ${movieName} on IMDb...`);
await util.fetch(url, {mode: 'cors'}).then(data => {
if (data !== undefined) {
terminal.stdout(true);
terminal.stdout(false, "<strong>Movie:</strong> ");
terminal.stdout(true, `${data.Title}`, "success");
terminal.stdout(false, "<strong>Year:</strong> ");
terminal.stdout(true, `${data.Year}`);
terminal.stdout(false, "<strong>Genre:</strong> ");
terminal.stdout(true, `${data.Genre}`);
terminal.stdout(false, "<strong>Released:</strong> ");
terminal.stdout(true, `${data.Released}`);
terminal.stdout(false, "<strong>Rated:</strong> ");
terminal.stdout(true, `${data.Rated}`);
terminal.stdout(false, "<strong>IMDB Rating:</strong> ");
terminal.stdout(true, `${data.imdbRating}`);
terminal.stdout(false, "<strong>Director:</strong> ");
terminal.stdout(true, `${data.Director}`);
terminal.stdout(false, "<strong>Writer:</strong> ");
terminal.stdout(true, `${data.Writer}`);
terminal.stdout(false, "<strong>Actors:</strong> ");
terminal.stdout(true, `${data.Actors}`);
terminal.stdout(true, "<strong>Extra:</strong> ");
terminal.stdout(true, `<a href="http://imdb.com/title/${data.imdbID}" target="_blank">View on IMDb</a>`);
terminal.stdout(true, `<a href="https://embed.smashystream.com/playere.php?imdb=${data.imdbID}" target="_blank">Watch on SmashyStream</a>`);
terminal.stdout(true);
terminal.stdout(true, "<strong>Plot:</strong> ");
terminal.stdout(true, util.wordBreak(data.Plot));
terminal.stdout(true);
} else {
terminal.stdout(true, "There was a problem retrieving your movie details..", "error");
terminal.stdout(true, "Check your spelling and try again.", "warn");
}
}).catch(error => {
console.log(error);
terminal.stdout(true, `bash: imdb: ` + util.wordBreak(error) + `\n`, "error");
});
}
}
});
terminal.registerCommand({
"name": "urlscan",
"type": "script",
"mime": "application/javascript",
"help": "<span class=\"cmd\">urlscan</span>: [<span class=\"host\">ip/domain</span>] [<span class=\"parameter\">--submit/--query</span>]\n\tSubmit or search domains/IPs for review with <a href=\"http://urlscan.io/\" target=\"_blank\">urlscan.io</a>\n\n\tSubmit a domain or IP address to urlscan.io and it'll begin to scan and\n\trecord the domains and IPs contacted, resource assets (JavaScript, CSS,\n\tetc) requested, as well as additional information about the page itself.\n\n\tYou can search existing scans by domains or IPs by using the <span class=\"parameter\">--query</span> flag.\n\n\tDefaults to <span class=\"parameter\">--submit</span> when no options are given.\n\n\tOptions:\n\t -s, --submit\tsubmit a domain/ip address for scanning\n\t -q, --query\tsearch existing scans\n\t -d, --domain\tthe domain to submit or search\n\t -i, --ip\tthe ip address to submit or search\n\n",
"func": async function (argv) {
console.log(argv);
if (argv.help || argv.h) {
const cmd = terminal.userCommands.find(cmd => cmd.name === 'urlscan');
terminal.stdout(true, cmd.help);
return;
}
const key = util.b64.de(`MWNkYTU2MDQtOTM5Ny00NjExLThiNjktZDEwMjQ4ZjhhNWFi`);
if (argv._.length !== 0) {
const movieName = argv._.join(' ');
const submit = (key, domain) => {
return new Promise(function (resolve, reject) {
const url = 'https://urlscan.io/api/v1/scan/';
const headers = {
'Content-Type': 'application/json',
'API-Key': key,
};
const body = JSON.stringify({
'url': domain,
'public': 'on',
});
fetch(url, {
method: 'POST',
headers: headers,
body: body,
})
.then(response => {
if (![200, 301, 302, 400, 427].includes(response.status)) {
resolve({
'statusCode': response.status,
'message': 'Hit the rate limit of 1 submission every 2 seconds.',
});
} else {
return response.json();
}
})
.then(body => resolve(body))
.catch(error => reject(error));
});
};
const check = (key, uuid) => {
const resultwait = setInterval(function () {
result(key, uuid).then(resultoutput => {
if (resultoutput.statusCode !== 404) {
// handle the results
console.log(JSON.stringify(resultoutput, null, 2));
clearInterval(resultwait);
}
});
}, 10 * 1000);
};
const result = (key, UUID) => {
return new Promise(function (resolve, reject) {
const url = 'https://urlscan.io/api/v1/result/' + UUID;
fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'API-Key': key,
},
})
.then(response => {
if (![200, 301, 302, 400].includes(response.status)) {
if (response.status === 400) {
return response.json();
}
resolve({
'statusCode': response.status,
'message': 'Scan not completed yet.',
});
} else {
return response.json();
}
})
.then(body => resolve(body))
.catch(error => reject(error));
});
};
const searchDomain = (key, domain) => {
return new Promise(function (resolve, reject) {
const url = 'https://urlscan.io/api/v1/search/?q=domain:' + domain;
fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'API-Key': key,
},
})
.then(response => {
if (response.status === 200) {
return response.json();
} else {
resolve({
'statusCode': 404,
'message': 'Failed to find what you were searching for.',
'total': 0,
'input': domain,
});
}
})
.then(body => resolve(body))
.catch(error => reject(error));
});
};
const searchIP = (key, ip) => {
return new Promise(function (resolve, reject) {
const url = 'https://urlscan.io/api/v1/search/?q=ip:"' + ip + '"';
fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'API-Key': key,
},
})
.then(response => {
if (response.status === 200) {
return response.json();
} else {
resolve({
'statusCode': 404,
'message': 'Failed to find what you were searching for.',
'total': 0,
'input': ip,
});
}
})
.then(body => resolve(body))
.catch(error => reject(error));
});
};
const domaintosubmit = argv.domain || argv.d;
const domaintoquery = argv.domain || argv.d;
const iptosubmit = argv.i || argv.ip;
const iptoquery = argv.i || argv.ip;
const submission = domaintosubmit || iptosubmit;
const query = iptoquery || domaintoquery;
if (argv.submission) {
terminal.stdout(true, `Submitting ${submission} to urlscan.io...`);
submit(key, submission).then(submitoutput => {
check(key, submitoutput.uuid);
});
return;
}
if (argv.query) {
terminal.stdout(true, `Searching for ${query} on urlscan.io...`);
if (argv.i || argv.ip) {
searchIP(key, iptoquery).then(searchoutput => {
check(key, searchoutput.results[0]._id);
});
return;
}
if (argv.d || argv.domain) {
searchDomain(key, domaintoquery).then(searchoutput => {
check(key, searchoutput.results[0]._id);
});
return;
}
}
}
}
});
terminal.vfs.tree.root.children.sort((a, b) => {
const A = a.name.toUpperCase();
const B = b.name.toUpperCase();
if (A < B) {
return -1;
}
if (A > B) {
return 1;
}
return 0;
});
terminal.userCommands.sort((a, b) => {
const A = a.name.toUpperCase();
const B = b.name.toUpperCase();
if (A < B) {
return -1;
}
if (A > B) {
return 1;
}
return 0;
});
terminal.userCommands.forEach(function (cmd) {
let exec = {
"name": cmd.name,
"type": cmd.type,
"link": cmd.link,
"permissions": "rwxr-xr-x",
"group": "root",
"user": "root",
"size": cmd.func.toString().length,
"modified": terminal.vfs.getDate(),
"mime": cmd.mime,
"contents": cmd.func.toString()
};
terminal.vfs.tree.insert(cmd, terminal.vfs._resolve_path("/usr/bin"), exec);
});
terminal.wakeUp();
function printWelcome() {
let welcomemsg = new Typed('.welcomemsg', {
strings: [terminal.options.welcome + "\n\nLast login: <span class=\"info\">" + date + "</span>"],
stringsElement: null,
typeSpeed: 40,
backSpeed: 40,
showCursor: false,
autoInsertCss: true,
onComplete: (self) => {
//printNext();
terminal.stdout(true);
terminal.renderPrompt();
}
});
}
$("<span />")
.addClass("welcomemsg")
.appendTo($(".container"));
printWelcome();
//terminal.stdout(true, "Last login: " + date, "info");
//terminal.stdout(true);
const init = () => {
terminal.renderPrompt();
};
//init();