MWSE/console/lib.js

908 lines
23 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

var term = new Terminal({
cursorStyle: "underline",
cols: 180,
rows: 50
});
term.open(document.querySelector('#terminal'));
function newLine(t = true, prompt = true) {
t && term.write('\r\n');
cursorPosition = 0;
if(prompt)
{
term.write(DEFAULT_PROMPT);
cursorPosition += CLEAR_STYLING(DEFAULT_PROMPT).length;
}
resetUserSpace()
}
let waitms = ms => new Promise(ok => setTimeout(()=>ok(), ms));
let cursorPosition = 0;
let _buffer = [];
let COLOR_RESET = () => "\x1B[0m";
let COLOR_TEXT = (r,g,b) => `\x1B[38;2;${r};${g};${b}m`;
let COLOR_BACKGROUND = (r,g,b) => `\x1B[48;2;${r};${g};${b}m`;
let CURSOR_MOVE = (row, col) => `\x1B[${row};${col}H`;
let CURSOR_MOVE_UP = () => `\x1B[A`;
let CURSOR_MOVE_DOWN = () => `\x1B[B`;
let CURSOR_MOVE_RIGHT = () => `\x1B[C`;
let CURSOR_MOVE_LEFT = () => `\x1B[D`;
let CLEAR_SCREEN = () => `\x1B[2J`;
let CLEAR_LINE = () => `\x1B[2K`;
term.write(CURSOR_MOVE(2,1));
let CLEAR_STYLING = (text) => text.toString().replace(/\x1B(.*?)m/ig,'');
function writeHi()
{
term.write(
"Merhaba, "
+ COLOR_TEXT(0,255,0)
+ COLOR_BACKGROUND(32,32,32)
+ ' saQut RC Shell '
+ COLOR_RESET()
+ "\n\n\r"
);
newLine();
}
let userSpace = {
buffer: [],
paddingChars: 0,
size: 0
};
function resetUserSpace()
{
userSpace = {
buffer: [],
paddingChars: 0,
size: 0
}
}
function getCurrentLine()
{
return term
.buffer
.active
.getLine(
term
.buffer
.active
.cursorY
)
.translateToString()
}
let pausedInput = false;
let activeProgram = false;
term.onData(async chars => {
if(pausedInput)
{
return
}
if(chars.length > 1)
{
return await DefaultProcess(chars);
}
if(chars.length == 1)
{
if(activeProgram)
{
if(activeProgram._sys.idleChar)
{
return activeProgram._sys.idleChar.triggerChar(chars);
}
}
return await DefaultProcess(chars);
}else if(activeProgram){
return
}
let tokens = [];
chars.toString().replace(/(\x1B.+?m)|(\x1B\[.+)|(.+)/igm, (_,a,b,c,d,e,f,g) => {
let charx = a || b || c;
if(charx)
{
if(/^(\x1B.*?m)$|^(\x1B\[.*)$/i.test(charx))
{
tokens.push([charx,])
}else{
tokens.push([,charx])
}
}
});
for (const [code, chars] of tokens)
{
pausedInput = true;
if(code)
{
await DefaultProcess(code);
}else if(chars)
{
for (const char of chars.split(''))
{
await DefaultProcess(char);
}
}
pausedInput = false;
}
})
async function DefaultProcess(char)
{
let contextchanged = false;
switch(char)
{
// Backspace
case '\x7f':
if(userSpace.paddingChars > 0)
{
term.write('\b \b');
cursorPosition--;
let after = userSpace.buffer.slice(0, userSpace.paddingChars - 1);
let before = userSpace.buffer.slice(userSpace.paddingChars);
userSpace.buffer = [
...after,
...before
];
userSpace.paddingChars--;
userSpace.size--;
contextchanged = true;
term.write(before.join('')+" \b");
term.write(before.map(() => '\b').join(''));
}
break;
// Enter
case '\r':
let command = userSpace.buffer.join('');
if(activeProgram && activeProgram._sys.idleReadline)
{
newLine(true, false);
return activeProgram._sys.triggerReadline(command);
}
let parsedCommand = ParseCommand(command);
if(parsedCommand != false)
{
let program = parsedCommand.find(e => e.type == 'commandname').data;
pausedInput = true;
newLine(true, false);
await ExecuteCommand(
program,
parsedCommand
);
pausedInput = false;
newLine(false);
}else{
newLine();
}
break;
case CURSOR_MOVE_LEFT():
if(userSpace.paddingChars > 0)
{
userSpace.paddingChars--;
term.write(CURSOR_MOVE_LEFT());
}
break;
case CURSOR_MOVE_UP():
case CURSOR_MOVE_DOWN():
break;
// Delete
case "\x1B[3~":
let after = userSpace.buffer.slice(0, userSpace.paddingChars);
let before = userSpace.buffer.slice(userSpace.paddingChars + 1);
term.write(before.join('')+" \b");
term.write(before.map(() => '\b').join(''));
userSpace.buffer = [
...after,
...before
];
userSpace.size--;
contextchanged = true;
break;
case CURSOR_MOVE_RIGHT():
if(userSpace.paddingChars < userSpace.size)
{
term.write(CURSOR_MOVE_RIGHT());
userSpace.paddingChars++;
}
break;
default:
let printable = char.charCodeAt(0);
if(printable < 32)
{
return
}
// insert or append ?
if(userSpace.paddingChars == userSpace.size)
{
term.write(char);
userSpace.buffer = [
...userSpace.buffer.slice(0, userSpace.paddingChars),
char,
...userSpace.buffer.slice(userSpace.paddingChars),
];
userSpace.paddingChars++;
userSpace.size++;
cursorPosition++;
contextchanged = true;
}else{
let after = userSpace.buffer.slice(0, userSpace.paddingChars);
let before = userSpace.buffer.slice(userSpace.paddingChars);
userSpace.buffer = [
...after,
char,
...before
];
term.write(char);
term.write(before.join(''));
term.write(before.map(() => '\b').join(''));
contextchanged = true;
userSpace.paddingChars++;
userSpace.size++;
cursorPosition++;
}
}
if(!activeProgram)
{
contextchanged && COLORIZE_LINE();
}
};
async function COLORIZE_LINE()
{
let before = userSpace.buffer.slice(0, userSpace.paddingChars);
let after = userSpace.buffer.slice(userSpace.paddingChars);
let coloredCommand = CommandColorize(before.concat(after).join(''));
if(coloredCommand)
{
// Cursoru en başa al
term.write(CURSOR_MOVE_LEFT().repeat(before.length));
term.write(coloredCommand);
term.write(CURSOR_MOVE_LEFT().repeat(after.length));
}
}
let USER_SPACE = "virtualhost";
let USER_NAME = [
147 + Math.random() * 25 | 0,
200 + Math.random() * 56 | 0,
0 + Math.random() * 256 | 0,
0 + Math.random() * 256 | 0
].join('.');
let DEFAULT_PROMPT = (
COLOR_RESET()
+ '['
+ COLOR_TEXT(0,255,0)
+ USER_SPACE
+ ' '
+ COLOR_TEXT(0,128,255)
+ USER_NAME
+ COLOR_RESET()
+ '] $ '
);
writeHi();
let _color_command = [255,255,255];
let _color_option = [128,128,255];
let _color_stringdata = [128,255,64];
function CommandColorize(command)
{
let hmx = new Hemex();
hmx.setText(command);
let output = [];
let commandBefore = hmx.of(() => !hmx.isLetter());
if(commandBefore.length != 0)
{
output.push(
COLOR_TEXT(255,255,255),
commandBefore,
COLOR_RESET()
)
}
if(!hmx.isLetter())
{
return false
}
let commandName = hmx.of(() => hmx.isLetter() || hmx.isNumber() || hmx.includes(['-','_',':','.','$']));
if(hmx.isEnd() && !hmx.isWhiteSpace())
{
return false
}
output.push(
COLOR_TEXT(..._color_command),
commandName,
COLOR_RESET()
);
let all = [], stringstarted = false;
hmx.each(() => {
let char = hmx.getChar();
switch(char)
{
case '\'':
case '"':
case '`':{
if(stringstarted == false)
{
stringstarted = char;
all.push(COLOR_TEXT(..._color_stringdata), char)
}else if(stringstarted == char){
stringstarted = false;
all.push(char, COLOR_TEXT(..._color_option))
}else{
all.push(char)
}
return true;
}
default:{
if(all.length == 0)
{
all.push(COLOR_TEXT(..._color_option), char);
}else{
all.push(char)
}
return true;
}
}
});
output.push(all.join(''))
output.push(COLOR_RESET())
return output.join('')
}
function ParseCommand(command)
{
let hmx = new Hemex();
hmx.setText(command);
hmx.of(() => !hmx.isLetter());
if(!hmx.isLetter())
{
return false
}
let onlyArgs = false;
let commandName = hmx.of(() => hmx.isLetter() || hmx.isNumber() || hmx.includes(['-','_',':','.','$']));
if(hmx.isEnd() && !hmx.isWhiteSpace())
{
return false
}
hmx.readWhiteSpace();
let args = [];
let xargs = [], operation = 'option';
hmx.beginPosition();
hmx.while(()=>{
if(hmx.include('--') && operation == 'option')
{
xargs.length && (
args.push({
type: 'data',
data: xargs.join('')
}),
xargs = []
);
hmx.beginPosition();
hmx.include('--', true);
let argumentkey = hmx.of(() => hmx.isLetter() || hmx.isNumber() || hmx.includes(['-','_',':','.','$']));
if(argumentkey == false)
{
hmx.rejectPosition();
return true;
}
args.push({
type: "argument",
data: argumentkey
});
hmx.acceptPosition();
hmx.readWhiteSpace();
return true;
}
if(hmx.include('-') && operation == 'option')
{
xargs.length && (
args.push({
type: 'data',
data: xargs.join('').trim()
}),
xargs = []
);
hmx.beginPosition();
hmx.nextChar();
let argumentkey = hmx.of(() => hmx.isLetter() || hmx.isNumber());
if(argumentkey == false)
{
hmx.rejectPosition();
return true;
}
argumentkey.split('').forEach(e => {
args.push({
type: "flag",
data: e
})
})
hmx.acceptPosition();
hmx.readWhiteSpace();
return true;
}
let char;
if((char = hmx.includes(['\'','"'])) && operation == 'option')
{
xargs.length && (
args.push({
type: 'data',
data: xargs.join('')
}),
xargs = []
);
let escapeChar = char[0];
hmx.nextChar();
let data = [];
hmx.while(() => {
let char = hmx.getChar();
switch(hmx.getChar())
{
case escapeChar:{
hmx.nextChar();
return false;
}
default:{
data.push(char);
hmx.nextChar();
return true;
}
}
});
args.push({
type: "string",
data: data.join('')
})
hmx.readWhiteSpace();
return true;
}
xargs.push(hmx.getChar());
if(hmx.isWhiteSpace())
{
operation = 'option';
}else{
operation = 'data';
}
hmx.nextChar();
if(hmx.isEnd())
{
return true;
}else{
args.push({
type: "data",
data: xargs.join('')
})
return false;
}
});
onlyArgs = hmx.getPositionRange();
hmx.acceptPosition();
return [{
type: "cmdline",
data: command
},{
type: "commandname",
data: commandName
},{
type: "arguments",
data: onlyArgs
}, ...args]
}
function generatepipe()
{
pausedInput = true;
let events = {};
let gen = {
stdin: {
setPaused(boolean){
pausedInput = Boolean(boolean);
},
async readline(){
gen.stdin.setPaused(false);
gen._sys.idleReadline = true;
return await new Promise(ok => {
events['readline'] = (result) => {
gen.stdin.setPaused(true);
gen._sys.idleReadline = false;
ok(result)
events['readline'] = null;
};
})
},
async getchar(){
gen.stdin.setPaused(false);
gen._sys.idleChar = true;
return await new Promise(ok => {
events['read'] = (result) => {
gen.stdin.setPaused(true);
gen._sys.idleChar = false;
events['read'] = null;
ok(result)
};
})
}
},
stdout: {
async write(...args){
term.write(args.map(e => e.toString()).join(' '))
},
async writeln(...args){
term.writeln(args.map(e => e.toString()).join(' '))
}
},
stderr: {
async write(...args){
term.write(COLOR_TEXT(255,0,0));
term.write(args.map(e => e.toString()).join(' '))
term.write(COLOR_RESET());
},
async writeln(...args){
term.write(COLOR_TEXT(255,0,0));
term.writeln(args.map(e => e.toString()).join(' '))
term.write(COLOR_RESET());
}
},
_sys:{
idleReadline: false,
idleChar: false,
triggerReadline(text){
if(events['readline']) events['readline'](text)
},
triggerChar(text){
if(events['read']) events['read'](text)
},
destroy(){
gen.stdin.setPaused(false);
events = void 0;
gen._sys.idleReadline = false;
gen._sys.idleChar = false;
gen._sys = void 0;
gen.stderr = void 0;
gen.stdin = void 0;
gen.stdout = void 0;
activeProgram = false;
}
}
};
activeProgram = gen;
return gen;
}
async function ExecuteCommand(command, cmdline)
{
let Namespace = await CommandNamespace(command);
if(Namespace == null)
{
return
}
try
{
await new Promise(async (ok,reject) => {
resetUserSpace();
let program = new Namespace(generatepipe());
program.exit = () => ok();
try{
let t = program.main(cmdline);
if(t?.constructor?.name == 'AsyncFunction')
{
await t;
}
}catch(e){
reject(e)
}
})
}
catch(exception)
{
term.writeln('');
term.write(COLOR_TEXT(255,0,0));
term.writeln('Yazılım hatası:');
term.writeln('=========================');
term.write(COLOR_RESET());
term.writeln(exception.message);
term.writeln(exception.stack.replace(/\n/g,'\r\n'));
term.write(COLOR_TEXT(255,0,0));
term.writeln('=========================');
term.write(COLOR_RESET());
}
finally
{
pausedInput = false;
activeProgram = void 0;
}
}
async function InspectRepo()
{
if(CommandNamespace.repos.find(e => e.downloaded == false))
{
term.writeln(COLOR_RESET()+"\r\nUpdating repos....")
await wait(100);
}else{
term.writeln('');
}
for(const repo of CommandNamespace.repos)
{
if(repo.downloaded == false)
{
term.writeln(`Downloading:${COLOR_TEXT(0,255,0)} ${repo.name} ${COLOR_RESET()} ${repo.endpoint}`);
await wait(100);
let file = await DownloadRepoMetapack(repo.endpoint);
repo.packages = file;
term.writeln(`Downloaded:${COLOR_TEXT(0,255,0)} ${repo.name} ${COLOR_RESET()} ${repo.endpoint}`);
await wait(100);
repo.downloaded = true;
}
}
return
}
async function CommandNamespace(command)
{
let package = false;
if(!CommandNamespace.namespaces.has(command))
{
await InspectRepo();
for(const repo of CommandNamespace.repos)
{
for (const repopackage in repo.packages)
{
let packageName = repopackage;
let meta = repo.packages[repopackage];
let _command = meta.commands.find(_command => command == _command);
if(_command)
{
package = [packageName,meta];
}
}
}
if(package == false)
{
term.writeln(COLOR_TEXT(255,0,0) + "'" + command + "' not found !" + COLOR_RESET());
}else{
term.writeln([
COLOR_TEXT(0,255,0),
package[0],
COLOR_TEXT(200,200,200),
" paketine ait olan ",
COLOR_TEXT(0,255,0),
command,
COLOR_TEXT(200,200,200),
" komutunu kullanabilmek için aşağıdaki komutunu çalıştırın"
].join('') +
"\r\n\n" +
CommandColorize(`load '${package[0]}' from 'official'`)+
"\n"
);
}
}else{
return CommandNamespace.namespaces.get(command);
}
}
function wait(ms)
{
return new Promise(ok => setTimeout(() => ok(),ms));
}
async function DownloadRepoMetapack(endpoint)
{
let request = await fetch(endpoint,{
method: "get",
cache: "force-cache",
priority: "high",
redirect: "follow",
referrerPolicy: "no-referrer"
});
await wait(100);
try{
let response = await request.json();
return response;
}catch
{
return null
}
}
CommandNamespace.namespaces = new Map();
CommandNamespace.repos = [{
name: "official",
endpoint: new URL('/console/official/packages.json',window.location),
downloaded: false,
packages: {}
}];
class SystemLoad{
stdin = null;
stdout = null;
constructor(pipe){
this.stdin = pipe.stdin;
this.stdout = pipe.stdout;
}
printhelp()
{
this.stdout.writeln('Kullanım şekli: ');
this.stdout.writeln('ExampleProgram paketini kurmak için aşağıdaki komutu yazmalısınız\r\n');
this.stdout.writeln(
CommandColorize(`load 'ExampleProgram'`)+"\r\n"
);
}
async main(args)
{
let m = false, nargs = args.filter(({type}) => {
if(type == "arguments") return m = true, false;
return m;
});
let packname;
if(nargs[0].type == "string")
{
packname = nargs[0].data;
}else{
this.printhelp();
this.exit();
return;
}
if(CommandNamespace.repos.find(e => e.downloaded == false))
{
this.stdout.writeln(COLOR_RESET()+"\r\nUpdating repos....")
}else{
this.stdout.writeln('');
}
for(const repo of CommandNamespace.repos)
{
if(repo.downloaded == false)
{
this.stdout.writeln(`Downloading:${COLOR_TEXT(0,255,0)} ${repo.name} ${COLOR_RESET()} ${repo.endpoint}`);
await wait(100);
let file = await DownloadRepoMetapack(repo.endpoint.href);
if(file == null){
continue
}
repo.packages = file;
this.stdout.writeln(`Downloaded:${COLOR_TEXT(0,255,0)} ${repo.name} ${COLOR_RESET()} ${repo.endpoint}`);
await wait(100);
repo.downloaded = true;
}
}
let endpoints = CommandNamespace.repos.map(e => e.packages[packname] && e.packages[packname].endpoints.map(endpoint => new URL(endpoint,e.endpoint))).filter(e => !!e)
if(endpoints.length == 0)
{
term.writeln(COLOR_TEXT(255,0,0) + "'" + packname + "' repo not found !" + COLOR_RESET());
await wait(100);
this.exit();
return;
}
for (const endpoint of endpoints[0])
{
let href = endpoint.href;
this.stdout.writeln(`Packet downloading :${COLOR_TEXT(0,255,0)} ${packname} ${COLOR_RESET()} ${endpoint.href}`);
await wait(100);
let request = await fetch(href,{
method: "get",
cache: "force-cache",
priority: "high",
redirect: "follow",
referrerPolicy: "no-referrer"
});
this.stdout.writeln(`Packet unzip to :${COLOR_TEXT(0,255,0)} /mount/xpack/${packname}/ ${COLOR_RESET()}`);
await wait(100);
let script = await request.text();
try{
this.stdout.writeln(`Analyzing..`);
await new Promise(ok => setTimeout(() => ok(),1000));
(new Function(script))();
this.stdout.writeln(`Process success`);
await wait(100);
}catch{
this.stderr.writeln(`Process error`);
await wait(100);
}
}
this.exit();
}
};
CommandNamespace.namespaces.set('load', SystemLoad);