Comparing version 1.0.4 to 3.0.0
441
index.js
#! /usr/bin/env node | ||
"use strict"; | ||
import fs from 'fs'; | ||
import chalk from 'chalk'; | ||
import axios from 'axios'; | ||
import resTime from './resTime.js'; | ||
import UserAgent from 'user-agents'; | ||
import { parse, stringify, toJSON } from 'flatted'; | ||
const pkg = JSON.parse(fs.readFileSync('./package.json')); | ||
import chalk from "chalk"; | ||
import axios from "axios"; | ||
import minimist from "minimist"; | ||
import resTime from "./resTime.js"; | ||
import UserAgent from "user-agents"; | ||
import Storage from "./modules/storage.js"; | ||
import { logo, error } from "./modules/utils.js"; | ||
const UA = new UserAgent(); | ||
const storage = new Storage(); | ||
import { help, version } from "./modules/info.js"; | ||
import { fetch } from "./modules/fetch.js"; | ||
import { addRelay, removeRelay, listRelays } from "./modules/settings.js"; | ||
resTime(axios); | ||
const command = process.argv[2]; | ||
var args = process.argv.slice(3) || []; | ||
var args = minimist(process.argv.slice(2)); | ||
const command = args?._; | ||
var config = { | ||
relays: [], | ||
log: {}, | ||
proxy: {} | ||
method: "GET", | ||
repeat: 1, | ||
history: {}, | ||
...storage.get(), | ||
}; | ||
if(fs.existsSync("./config.json")) config = JSON.parse(fs.readFileSync('./config.json', 'utf-8')); | ||
else fs.writeFileSync('./config.json', JSON.stringify(config)); | ||
var log = config?.log || {}; | ||
var url; | ||
var method; | ||
var data; | ||
var output; | ||
var headers; | ||
var remove = false; | ||
var type; | ||
var repeat; | ||
var useRelay = false; | ||
var wait = 0; | ||
var userAgent; | ||
var useProxy; | ||
const commands = { | ||
fetch, relay, version, ["-v"]: version, ["--version"]: version, help, ["-h"]: help, ["--help"]: help, proxy | ||
}; | ||
function processArgs() { | ||
for (var option in args) { | ||
switch (option) { | ||
case "u": | ||
case "url": | ||
config.url = args[option]; // url to request | ||
break; | ||
function getArgsData(type, arg) { | ||
if(arg.length == 0) return log[`${type}`]; | ||
else return arg; | ||
} | ||
case "m": | ||
case "method": | ||
config.method = args[option]; // request method | ||
break; | ||
function getArgs() { | ||
if(!args || args.length == 0) return; | ||
args.forEach((e, i) => { | ||
switch(e) { | ||
case "-u": | ||
case "--url": | ||
url = getArgsData("url", args[i+1]); | ||
case "o": | ||
case "output": | ||
config.output = args[option]; // output file | ||
break; | ||
case "-m": | ||
case "--method": | ||
method = getArgsData("method", args[i+1]); | ||
case "d": | ||
case "display": | ||
config.display = true; // display portion data | ||
break; | ||
case "-d": | ||
case "--data": | ||
data = getArgsData("data", args[i+1]); | ||
case "r": | ||
case "repeat": | ||
if (isNaN(Number(args[option]))) | ||
error( | ||
"Invalid repeat value:", | ||
args[option], | ||
"[-r or --repeat <number>]" | ||
); | ||
config.repeat = Number(args[option]); // repeat request | ||
break; | ||
case "-o": | ||
case "--output": | ||
output = getArgsData("output", args[i+1]); | ||
case "w": | ||
case "wait": | ||
if (isNaN(Number(args[option]))) | ||
error( | ||
"Invalid wait value:", | ||
args[option], | ||
"[-w or --wait <milliseconds>]" | ||
); | ||
config.wait = Number(args[option]); // wait before request | ||
break; | ||
case "-t": | ||
case "--type": | ||
type = getArgsData("type", args[i+1]); | ||
case "H": | ||
case "headers": | ||
config.headers = JSON.parse(args[option]); // request header | ||
break; | ||
case "-r": | ||
case "--repeat": | ||
if(isNaN(Number(args[i+1]))) return error("Invalid repeat value", args[i+1], '-r or --repeat <number>'); | ||
repeat = getArgsData("repeat", args[i+1]); | ||
case "B": | ||
case "body": | ||
config.body = args[option]; // request body | ||
case "useragent": | ||
config.userAgent = args[option]; // request user agent | ||
break; | ||
case "-w": | ||
case "--wait": | ||
if(isNaN(Number(args[i+1]))) return error("Invalid wait value", args[i+1], '-w or --wait <number>'); | ||
wait = getArgsData("wait", args[i+1]); | ||
case "t": | ||
case "timeout": | ||
config.timeout = args[option]; // request timeout in milliseconds | ||
break; | ||
case "-re": | ||
case "--relay": | ||
useRelay = true; | ||
case "p": | ||
case "proxy": | ||
var value = args[option].split("@"); | ||
var user = value.length == 2 ? value[0] : null; | ||
var proxy = (value.length == 1 ? value[0] : value[1]).split(":"); | ||
if (user) | ||
user = { | ||
username: user.split(":")[0], | ||
password: user.split(":")[1], | ||
}; | ||
config.proxy = { | ||
// request proxy | ||
host: proxy[0], | ||
port: proxy[1], | ||
user, | ||
}; | ||
break; | ||
case "-rm": | ||
case "--remove": | ||
remove = true; | ||
case "relay": | ||
if ( | ||
!config?.relays || | ||
!Array.isArray(config?.relays) || | ||
!config?.relays[0] | ||
) | ||
error( | ||
"No relays were found therefore can't be used", | ||
"FETCH", | ||
`${chalk.green(`loh --listrelays`)}`, | ||
true | ||
); | ||
const random = | ||
(config?.relays[ | ||
Math.floor(Math.random() * config?.relays.length) | ||
]).split("@"); | ||
config.useRelay = { | ||
url: random[0], | ||
password: random[1] ? random[1] : null, | ||
}; | ||
break; | ||
case "-H": | ||
case "--headers": | ||
headers = getArgsData("headers", args[i+1]); | ||
break; | ||
case "-ua": | ||
case "--useragent": | ||
userAgent = getArgsData("useragent", args[i+1]); | ||
break; | ||
case "-p": | ||
case "--proxy": | ||
if(!config?.proxy) return error("No proxy was found", "PROXY", `${chalk.green(`loh proxy`)}`); | ||
useProxy = config?.proxy; | ||
break; | ||
} | ||
}) | ||
} | ||
} | ||
getArgs(); | ||
if(command == "rr" || command == "rerun") { | ||
if(!log?.command || log?.command == "rr") error("No command to rerun"); | ||
else { args = log.args; getArgs(); commands[log?.command](); } | ||
}else { | ||
if(!command) help() | ||
else if(command && !commands[`${command}`]) error("Command not found"); | ||
else { commands[`${command}`](); fs.writeFileSync('./config.json', JSON.stringify({ ...config, log: { url, method, useRelay, useProxy, data, output, command, args, type, userAgent, headers } })); } | ||
} | ||
const commands = { | ||
help, | ||
version, | ||
fetch, | ||
addRelay, | ||
removeRelay, | ||
listRelays, | ||
}; | ||
if(!isNaN(repeat)) { | ||
for(let i = 0; i < repeat; i++) { | ||
setTimeout(() => { | ||
commands[log?.command](); | ||
}, wait * i); | ||
} | ||
} | ||
function parseType(type, data) { | ||
const separator = type.split("|"); | ||
var output = ""; | ||
separator.forEach((e) => { | ||
output += `${typeof data?.[`${e}`] == 'object' ? stringify(data?.[`${e}`]) : data?.[`${e}`]}\n`; | ||
}); | ||
return output; | ||
} | ||
function json(str) { | ||
try { | ||
return JSON.parse(str); | ||
} catch (e) { | ||
return str; | ||
} | ||
} | ||
function fetch() { | ||
const fetchError = (message, showExample = true) => error(message, "FETCH", showExample ? `${chalk.green(`loh fetch`)} <url:required> <method> <data> <output> <type> <repeat> <wait> <relay>` : null); | ||
if(!url) return fetchError("No URL provided"); | ||
var packet = { | ||
proxy: useProxy, method: method ? method : 'GET', url, data: json(data), headers: { "User-Agent": userAgent ? userAgent : UA.toString(), ...json(headers) } | ||
(async () => { | ||
if (command == "rr" || command == "rerun") { | ||
const { history } = storage.get(); | ||
if (!history?.command) | ||
error( | ||
"There are no previous command to be rerun", | ||
"lohjs", | ||
"lohjs <command>", | ||
true | ||
); | ||
args = { | ||
...history?.args, | ||
...args, | ||
}; | ||
if(useRelay && config?.relays?.length > 0) packet = { url: config.relays[Math.floor(Math.random() * config.relays.length)], data: packet, method: "POST" }; | ||
else if(useRelay && config?.relays?.length == 0) fetchError("No relays were found, using local fetch...", false); | ||
axios(packet).then(res => { | ||
var data; | ||
if(type) data = parseType(type, res); | ||
else data = res; | ||
if(typeof data == "object") data = stringify(data); | ||
if(output){ | ||
fs.writeFileSync(output, `${data}`); | ||
response("Data saved to " + output); | ||
} | ||
response(` | ||
${useRelay ? chalk.blue(`RELAY `) : ''}Fetched data with status code ${res.status} | ||
User Agent: ${chalk.yellow(userAgent ? userAgent : 'Random')} | ||
${res?.data ? chalk.grey((`${typeof res?.data == 'object' ? JSON.stringify(res?.data) : res?.data}`).substring(0,100)) : 'No Response Data'} | ||
`); | ||
}).catch(err => { | ||
var data; | ||
repeat = 0; | ||
if(type) data = parseType(type, err); | ||
else data = err; | ||
if(typeof data == "object") data = stringify(data); | ||
if(output){ | ||
fs.writeFileSync(output, `${data}`); | ||
response("Error log saved to " + output); | ||
} | ||
return fetchError(`${useRelay ? `${chalk.yellow(`Relay used: ${packet.url}`)} ` : ''} | ||
${err} | ||
${err.response.data ? chalk.grey(err.response.data.substring(0, 100)) : 'No response data'} | ||
`); | ||
}) | ||
processArgs(); | ||
runCommand(history?.command); | ||
} else { | ||
var storageData = storage.get(); | ||
storageData = { | ||
...storageData, | ||
history: { | ||
command, | ||
args, | ||
}, | ||
}; | ||
await storage.set(storageData); | ||
processArgs(); | ||
if (command == "help" || args.help) runCommand("help"); | ||
if (command == "version" || args.version) runCommand("version"); | ||
if (command == "fetch" || args.fetch) runCommand("fetch"); | ||
if (args.addrelay) runCommand("addRelay"); | ||
if (args.removerelay) runCommand("removeRelay"); | ||
if (args.listrelays) runCommand("listRelays"); | ||
} | ||
})(); | ||
function runCommand(command) { | ||
if (!commands[command]) | ||
error("Invalid command:", command, "lohjs <command>", true); | ||
commands[command]({ | ||
command, | ||
chalk, | ||
axios, | ||
logo, | ||
storage, | ||
config, | ||
UA, | ||
error, | ||
args, | ||
}); | ||
} | ||
function proxy() { | ||
const proxyError = (message, showExample = true) => error(message, "PROXY"); | ||
if(!args[0]) { | ||
if(!config?.proxy) return proxyError("No proxy was found"); | ||
else return response(`Current proxy: ${stringify(config.proxy)}`); | ||
}else { | ||
if(remove) { config.proxy = {}; return response("Proxy removed"); } | ||
try { | ||
config.proxy = JSON.parse(args[0]); | ||
response(`Proxy set to ${JSON.stringify(config.proxy)}`); | ||
}catch(e) { | ||
proxyError("Invalid proxy format"); | ||
} | ||
} | ||
} | ||
function relay() { | ||
const relayError = (message) => error(message, "RELAY", `${chalk.green(`loh relay`)} <url: to add or remove> <remove: to remove>`); | ||
if(!Array.isArray(config?.relays)) config.relays = []; | ||
if(url) { | ||
if(remove) { | ||
const index = config?.relays?.indexOf(`${url}`); | ||
if (index > -1) { config?.relays?.splice(index, 1); return response("Removed relay " + url); } | ||
else return relayError("Relay url not found"); | ||
}else { | ||
if(config?.relays?.includes(`${url}`)) return relayError("relay url already exist."); | ||
config.relays.push(url); | ||
fs.writeFileSync('./config.json', JSON.stringify(config)); | ||
return response("Relay added", url); | ||
} | ||
}else { | ||
if(config.relays.length == 0) return relayError("No relays were found"); | ||
var rp = ''; | ||
rp += `Relays: ${config.relays.length}\n`; | ||
config.relays.forEach((e, i) => { | ||
rp += ` | ||
${chalk.yellow(`${i+1}. ${e}`)}` | ||
}) | ||
return response(rp); | ||
} | ||
} | ||
function error(message, error, example) { | ||
console.log(chalk.red(` | ||
${message ? chalk.magenta(`loh error: ${error}`) : ''} | ||
Error: | ||
${message} | ||
${example ? chalk.blue(`Example: ${example}`) : ''} | ||
`)); | ||
} | ||
function response(...message) { | ||
console.log(chalk.green(` | ||
${message.join(" ")} | ||
`)); | ||
} | ||
async function version() { | ||
const { data } = await axios.get("https://raw.githubusercontent.com/codingstudios/loh/main/package.json"); | ||
console.log(` | ||
${logo()} | ||
-------------------- | ||
Latest Version: ${chalk.green(`v${data.version}`)} | ||
-------------------- | ||
Github: ${chalk.yellow(`https://github.com/CodingStudios/loh`)} | ||
Author: ${chalk.green(`https://github.com/leecheeyong`)} & ${chalk.green(`https://github.com/joeleeofficial`)} | ||
License: ${chalk.blue(`AGPL-3.0 (https://github.com/CodingStudios/loh/blob/main/LICENSE)`)} | ||
${chalk.grey(`Use ${chalk.green(`loh help`)} to view all commands`)} | ||
`); | ||
} | ||
function help() { | ||
console.log(` | ||
${logo()} | ||
Github: ${chalk.yellow(`https://github.com/CodingStudios/loh`)} | ||
Author: ${chalk.green(`https://github.com/leecheeyong`)} & ${chalk.green(`https://github.com/joeleeofficial`)} | ||
License: ${chalk.blue(`AGPL-3.0 (https://github.com/CodingStudios/loh/blob/main/LICENSE)`)} | ||
Commands: | ||
${chalk.magenta(` | ||
fetch (f) Do a fetch request | ||
rerun (rr) Rerun previous command with its options | ||
relay (p) Add or remove relays | ||
version (v) View current and latest version | ||
help (h) View all commands | ||
`)} | ||
Options: | ||
${chalk.magenta(` | ||
-u, --url Url to fetch | ||
-t, --type Type of data to output | ||
-o, --output Output file to save data | ||
-m, --method Method to use | ||
-re, --relay Use relay | ||
-rm, --remove Remove | ||
-d, --data Body of the request | ||
-H, --headers Headers of the request | ||
-ua, --useragent User agent of the request | ||
`)} | ||
Usage: ${chalk.blue(`loh <command> [options]`)} | ||
Example: ${chalk.yellow(`loh fetch -u https://example.com -method GET`)} | ||
`) | ||
} | ||
function logo() { | ||
return ` | ||
${chalk.yellow(`== === ==`)} | ||
${chalk.blue(`== == == =======`)} | ||
${chalk.red(`== == == == ==`)} | ||
${chalk.green(`=== == == == == ==`)} | ||
${chalk.yellow(`=== == === == ==`)} | ||
${chalk.blue(`loh ${chalk.blue(`v${pkg.version}`)}`)} | ||
`.split("=").join(`${["$", "=", "/"][Math.floor(Math.random() * 3)]}`) | ||
} | ||
/* | ||
APG-3.0 License: https://github.com/codingstudios/loh/blob/main/LICENSE | ||
Author: Lee Chee Yong | ||
*/ | ||
*/ |
{ | ||
"name": "loh", | ||
"version": "1.0.4", | ||
"version": "3.0.0", | ||
"bin": { | ||
@@ -25,7 +25,10 @@ "loh": "index.js" | ||
"dependencies": { | ||
"axios": "^1.1.3", | ||
"chalk": "^5.1.2", | ||
"axios": "^1.4.0", | ||
"chalk": "^5.2.0", | ||
"flatted": "^3.2.7", | ||
"user-agents": "^1.0.1179" | ||
"minimist": "^1.2.8", | ||
"prettier": "^2.8.8", | ||
"socks-proxy-agent": "^8.0.1", | ||
"user-agents": "^1.0.1378" | ||
} | ||
} |
100
readme.md
@@ -12,2 +12,3 @@ # loh | ||
yarn global add loh # yarn | ||
npx loh | ||
``` | ||
@@ -23,88 +24,41 @@ | ||
### Re-run command with options | ||
You can easily rerun previous commands, such as fetch without re-inputting the options | ||
### Re-run commands | ||
You can easily rerun previous commands (and make changes) | ||
``` | ||
$ loh rerun | ||
# This will run the previous command in the background without having you to retype them | ||
``` | ||
You can also see the list of available commands using the `loh help` command. | ||
Run `loh help` to see the list of available commands and options | ||
## Options | ||
### Repeat & delay | ||
You can easily do a same fetch request multiple times with the option to set a delay for each request | ||
``` | ||
$ loh fetch -u https://example.com --repeat 10 # Do a fetch request 11 times (repeat the same fetch 10 times) | ||
$ loh fetch -u https://example.com --repeat 10 -wait 2000 # Do a total of 11 fetch request with 2000 milliseconds of delay each | ||
``` | ||
| **Option** | **Description** | **Example** | | ||
| ---------- | --------------- | ----------- | | ||
| `-u`, `--url` | Specify the url to make request to | `loh fetch -u https://example.com` | | ||
| `-m`, `--method` | Specify the request method | `loh fetch -u https://example.com -m POST` | | ||
| `-o`, `--output` | Specify a filename for response output | `loh fetch -u https://loh.js.org -o output.txt` | | ||
| `-d`, `--display` | Display some output data as preview | `loh fetch -u https://loh.js.org --display` | | ||
| `-r`, `--repeat` | Specify the amount of requests to make repeatedly | `loh fetch -u https://loh.js.org -r 5` | | ||
| `-w`, `--wait` | Specify the time to wait in (ms) before the next request is made | `loh fetch -u https://loh.js.org --wait 1000 -r 5` | | ||
| `-H`, `--headers` | Set the request header | `loh fetch -u https://loh.js.org --headers '{"Authorization": "Bearer 1234"}'` | | ||
| `-B`, `--body` | Set the request body | `loh fetch -u https://loh.js.org --method POST --body '{"value": "hello world"}'` | | ||
| `-p`, `--proxy` | Set the request proxy | `loh fetch -u https://loh.js.org --proxy user:password@127.0.0.1:9050` | | ||
| `--relay` | Use a random fetch relay to make the request | `loh fetch -u https://loh.js.org --relay` | | ||
### Set Headers | ||
Set a JSON header | ||
## Configure Relays | ||
loh supports [Relay Server](https://github.com/codingstudios/relay-server) | ||
``` | ||
$ loh fetch -u https://example.com --headers '{"Authorization":"123456"}' --method POST | ||
``` | ||
# add relay | ||
$ loh --addrelay https://relayserver.example | ||
### Set body | ||
Set the request body as text or JSON | ||
``` | ||
$ loh fetch -u https://example.com --body '{"value":"hello"}' --method POST | ||
``` | ||
# remove relay | ||
$ loh --removerelay https://relayserver.example | ||
### Set User Agent | ||
Set the user agent (**Note: a random user agent will be generated and used automatically**) | ||
# list relay | ||
$ loh --listrelays https://relayserver.example | ||
``` | ||
$ loh fetch -u https://example.com --useragent loh | ||
``` | ||
### Set Output & format data | ||
Set a file to save output data | ||
``` | ||
$ loh fetch -u https://example.com --output ./output.txt | ||
$ loh fetch -u https://example.com --output ./output.txt --type 'status|data|timings' | ||
``` | ||
Example output data of the second line: | ||
``` | ||
200 | ||
This is a response body | ||
[{"timingEnd":1666711647530,"timingStart":1666711647117,"elapsedTime":413}] | ||
``` | ||
## Proxy | ||
Use a proxy server | ||
### Use proxy server to do a request | ||
``` | ||
$ loh fetch --url https://example.com -p | ||
``` | ||
#### Set a proxy server | ||
``` | ||
$ loh proxy '{"proxy":{"host":"proxy-url","port":80,"auth":{"username":"my-user","password":"my-password"}}' | ||
``` | ||
#### Remove proxy | ||
``` | ||
$ loh proxy --remove | ||
``` | ||
## Relay | ||
loh supports [relay-server](https://github.com/codingstudios/Fetch-Relay/tree/main/relayServer) | ||
### Use relay in a request | ||
``` | ||
$ loh fetch -u https://example.com --relay | ||
``` | ||
#### Set relay | ||
``` | ||
$ loh relay --url https://proxy.example.com | ||
``` | ||
#### Delete relay | ||
``` | ||
$ loh relay --url https://proxy.example.com --remove | ||
``` | ||
#### View the list of relays | ||
``` | ||
$ loh relay | ||
``` | ||
## Contributors | ||
- [@leecheeyong](https://github.com/leecheeyong) | ||
- [@joeleeofficial](https://github.com/joeleeofficial) | ||
- [Contributors from @CodingStudios](https://github.com/codingstudios) | ||
@@ -115,6 +69,2 @@ | ||
This project is available as open source under the terms of the [AGPL-3.0 License](https://github.com/codingstudios/loh/blob/main/LICENSE) | ||
This project is available as open source under the terms of the [AGPL-3.0 License](https://github.com/codingstudios/loh/blob/main/LICENSE) |
@@ -41,1 +41,2 @@ "use strict"; | ||
}; | ||
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 3 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
53221
10
552
7
67
6
2
+ Addedminimist@^1.2.8
+ Addedprettier@^2.8.8
+ Addedsocks-proxy-agent@^8.0.1
+ Addedagent-base@7.1.3(transitive)
+ Addeddebug@4.4.0(transitive)
+ Addedip-address@9.0.5(transitive)
+ Addedjsbn@1.1.0(transitive)
+ Addedminimist@1.2.8(transitive)
+ Addedms@2.1.3(transitive)
+ Addedprettier@2.8.8(transitive)
+ Addedsmart-buffer@4.2.0(transitive)
+ Addedsocks@2.8.3(transitive)
+ Addedsocks-proxy-agent@8.0.5(transitive)
+ Addedsprintf-js@1.1.3(transitive)
+ Addeduser-agents@1.1.444(transitive)
- Removeduser-agents@1.1.448(transitive)
Updatedaxios@^1.4.0
Updatedchalk@^5.2.0
Updateduser-agents@^1.0.1378