Skip to content

Commit 309084a

Browse files
Let there be light
1 parent 6500bf1 commit 309084a

File tree

8 files changed

+4808
-0
lines changed

8 files changed

+4808
-0
lines changed

README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Techstack CLI
2+
3+
#### CLI app to reveal tech stack of an enterprise (CLI wrapper for [Wappalyzer](https://www.npmjs.com/package/wappalyzer))
4+
5+
#### Steps to use
6+
7+
- Download ```node```
8+
- Run the following command on terminal
9+
```sh
10+
npm install -g techstack-cli
11+
source ~/.bashrc
12+
techstack 'https://www.netflix.com'
13+
```
14+
#### Examples
15+
Try for a single url
16+
```sh
17+
techstack 'https://www.github.com'
18+
```
19+
<img src="./example-images/single.png"
20+
alt="Single example"
21+
style="float: left; margin-right: 10px;" />
22+
Or more than one url (<b>upto 10</b>)
23+
<img src="./example-images/double.png"
24+
alt="Single example"
25+
style="float: left; margin-right: 10px;" />
26+
27+
Feel free to contribute. Happy hacking :)

example-images/double.png

161 KB
Loading

example-images/single.png

104 KB
Loading

package.json

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
{
2+
"name": "techstack-cli",
3+
"version": "1.0.0",
4+
"description": "CLI app for detecting technologies behind a company",
5+
"main": "src/index.js",
6+
"repository": "git@github.com:existentialcoder/TechstackCLI.git",
7+
"author": "existentialcoder <shravanayyappa@gmail.com>",
8+
"license": "MIT",
9+
"private": false,
10+
"keywords": ["techstack", "technologies stack", "Technologies Stack", "Companies Tehnologies", "Wappalyzer", "wappalyzer-cli", "Wappalyzer Command Line", "wappalyzer cli"],
11+
"bin": {
12+
"techstack": "./src/"
13+
},
14+
"engine": {
15+
"node": "10"
16+
},
17+
"scripts": {
18+
"unit": "nyc jest --detectOpenHandles",
19+
"test": "yarn unit",
20+
"lint": "eslint -f table .",
21+
"dev": "node src"
22+
},
23+
"eslintConfig": {
24+
"env": {
25+
"node": true,
26+
"jest": true
27+
},
28+
"parserOptions": {
29+
"ecmaVersion": 2018
30+
},
31+
"extends": "airbnb-base",
32+
"overrides": [
33+
{
34+
"files": [
35+
"*.js"
36+
],
37+
"rules": {}
38+
},
39+
{
40+
"files": [
41+
"*.spec.js"
42+
],
43+
"rules": {
44+
"max-lines": [
45+
"error",
46+
1500
47+
],
48+
"max-lines-per-function": [
49+
"error",
50+
1500
51+
],
52+
"no-unused-expressions": "off",
53+
"no-empty-function": "off",
54+
"init-declarations": "off",
55+
"no-magic-numbers": "off",
56+
"func-names": "off",
57+
"semi": "off",
58+
"global-require": "off"
59+
}
60+
}
61+
]
62+
},
63+
"nyc": {
64+
"check-coverage": true,
65+
"per-file": true,
66+
"lines": 90,
67+
"statements": 90,
68+
"functions": 90,
69+
"reporter": [
70+
"html",
71+
"text-summary",
72+
"text"
73+
]
74+
},
75+
"eslintIgnore": [
76+
"node_modules/"
77+
],
78+
"dependencies": {
79+
"chalk": "^4.1.0",
80+
"commander": "^6.0.0",
81+
"console-table-printer": "^2.2.6",
82+
"wappalyzer": "^6.2.1"
83+
},
84+
"devDependencies": {
85+
"eslint": "^7.5.0",
86+
"eslint-config-airbnb-base": "^14.1.0",
87+
"eslint-plugin-import": "^2.22.0",
88+
"jest": "^26.2.2",
89+
"jest-mock-process": "^1.4.0",
90+
"nyc": "^15.1.0"
91+
}
92+
}

src/index.js

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#!/usr/bin/env node
2+
3+
const { execSync } = require('child_process');
4+
const Wappalyzer = require('wappalyzer');
5+
const logger = require('./utils/logger');
6+
const { messages, units } = require('./utils/constants');
7+
8+
const getURLList = () => {
9+
const args = process.argv;
10+
return args.slice(2);
11+
};
12+
13+
const getTechResponse = async (urls) => {
14+
const wappalyzer = await new Wappalyzer({
15+
maxWait: units.ONE_MINUTE,
16+
recursive: true,
17+
userAgent: 'Wappalyzer',
18+
htmlMaxCols: 2000,
19+
htmlMaxRows: 2000,
20+
});
21+
22+
await wappalyzer.init();
23+
24+
const results = await Promise.all(
25+
urls.map(async (url) => ({
26+
url,
27+
results: await wappalyzer.open(url).analyze(),
28+
})),
29+
);
30+
31+
await wappalyzer.destroy();
32+
return results;
33+
};
34+
35+
const getUserName = () => {
36+
const userName = execSync('whoami');
37+
return String(userName).replace('\n', '');
38+
};
39+
40+
const getIsValidUrls = (urls) => {
41+
try {
42+
urls.forEach((url) => new URL(url));
43+
return true;
44+
} catch (er) {
45+
return false;
46+
}
47+
};
48+
49+
const printResult = (response) => {
50+
logger.log('\nHoorah! Your results are ready');
51+
response.forEach((urlRes) => {
52+
logger.log(`\nTechnologies used in ${urlRes.url} are \n`);
53+
const techTable = urlRes.results.technologies
54+
.map(({ name, website }) => ({ Name: name, Website: website }));
55+
56+
logger.table([...new Set(techTable)]);
57+
});
58+
};
59+
60+
const techstackCLI = async (args) => {
61+
const userName = getUserName();
62+
63+
logger.log(messages.WELCOME_MSG(userName));
64+
const urls = args || getURLList();
65+
66+
const validUrl = getIsValidUrls(urls);
67+
68+
if (!urls || !urls.length || !validUrl) {
69+
logger.error(messages.INVALID_INPUT);
70+
process.exit();
71+
}
72+
73+
try {
74+
const techResponse = await getTechResponse(urls);
75+
76+
printResult(techResponse);
77+
process.exit();
78+
} catch (er) {
79+
logger.error(messages.WAPP_ERROR);
80+
}
81+
};
82+
83+
techstackCLI();
84+
85+
const CLI = { techstackCLI, getTechResponse };
86+
module.exports = CLI;

src/utils/constants.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module.exports = {
2+
messages: {
3+
INVALID_INPUT: 'Please include a valid link',
4+
WAPP_ERROR: 'Something wrong. Check your network',
5+
WELCOME_MSG: (name) => `Hey ${name}! Please wait while we process ...`,
6+
},
7+
units: {
8+
ONE_MINUTE: 60 * 1000,
9+
},
10+
};

src/utils/logger.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
const { Table } = require('console-table-printer');
2+
const chalk = require('chalk');
3+
4+
const { log, error } = console;
5+
const table = new Table();
6+
7+
const logger = {
8+
log(msg, color = 'blue') {
9+
return log(
10+
chalk[color](msg),
11+
);
12+
},
13+
error(msg, color = 'red') {
14+
return error(
15+
chalk[color](msg),
16+
);
17+
},
18+
table(arr) {
19+
arr.forEach((arrVal) => table.addRow(arrVal, { color: 'green' }));
20+
table.printTable();
21+
},
22+
};
23+
24+
module.exports = logger;

0 commit comments

Comments
 (0)