Compare commits
86 Commits
FIX/chromi
...
1.0.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7234e11e87 | ||
|
|
031b0e37bb | ||
|
|
f1fff427f8 | ||
|
|
584c145b15 | ||
|
|
d9e7bb57f3 | ||
|
|
c9631e6848 | ||
|
|
06965b0e82 | ||
|
|
be741a1087 | ||
|
|
52b3960ce3 | ||
|
|
d7bcbcb5b4 | ||
|
|
4d54cdccac | ||
|
|
da75fb25d7 | ||
|
|
42023039c1 | ||
|
|
affec03d6c | ||
|
|
ecaffda777 | ||
|
|
0d484e3ffa | ||
|
|
38d6b5b97e | ||
|
|
728a8237aa | ||
|
|
24ca677021 | ||
|
|
ed53c29a55 | ||
|
|
c4e29fda0f | ||
|
|
ff65696729 | ||
|
|
2304aaf17c | ||
|
|
d43a05a0ed | ||
|
|
ada1dccc5b | ||
|
|
7a8e694abc | ||
|
|
c764bbfcd4 | ||
|
|
523419df11 | ||
|
|
62a213d74d | ||
|
|
7fc8ba4c15 | ||
|
|
f63418039a | ||
|
|
3f80d58085 | ||
|
|
ee74c5866a | ||
|
|
41cd379805 | ||
|
|
0c5dbd66a3 | ||
|
|
18f72788aa | ||
|
|
cd3ab4a264 | ||
|
|
ab66def695 | ||
|
|
68778d3824 | ||
|
|
43851ae0fb | ||
|
|
91a6e6221c | ||
|
|
7f2da1905c | ||
|
|
7583843e80 | ||
|
|
e77075764e | ||
|
|
195577fe0c | ||
|
|
29398665b0 | ||
|
|
1780b2323d | ||
|
|
1e6802afbf | ||
|
|
2cd68c5b98 | ||
|
|
ac3a70ae0d | ||
|
|
761f9dab81 | ||
|
|
64fbcb3f7d | ||
|
|
2fb7dc9a2b | ||
|
|
0a1023ce19 | ||
|
|
f4dd5d7a31 | ||
|
|
aff5ea5f52 | ||
|
|
4c4813620d | ||
|
|
b9bc24156b | ||
|
|
13d0e4ac9f | ||
|
|
01fb32e43c | ||
|
|
ec30ef7b8b | ||
|
|
af70930be2 | ||
|
|
55299f001f | ||
|
|
7e51239c8d | ||
|
|
cb6a008680 | ||
|
|
55f30f5537 | ||
|
|
cc3ca64f25 | ||
|
|
8c0cf5f870 | ||
|
|
2f46de124d | ||
|
|
0db0b044b2 | ||
|
|
299925d22e | ||
|
|
db9b69fac3 | ||
|
|
be307e6876 | ||
|
|
e44f8e73aa | ||
|
|
9c4335f2af | ||
|
|
44cbe47983 | ||
|
|
5924d89f54 | ||
|
|
b5ec08da8b | ||
|
|
184b962731 | ||
|
|
d6035b8e9c | ||
|
|
2988486a65 | ||
|
|
5616b71564 | ||
|
|
5348175b5e | ||
|
|
f9b4edda01 | ||
|
|
50590334be | ||
|
|
33a35b94f5 |
11
.env
11
.env
@@ -18,8 +18,9 @@ REACT_APP_WHO_API_KEY=''
|
|||||||
|
|
||||||
# Configuration settings
|
# Configuration settings
|
||||||
# CHROME_PATH='/usr/bin/chromium' # The path the the Chromium executable
|
# CHROME_PATH='/usr/bin/chromium' # The path the the Chromium executable
|
||||||
# PORT='3000' # Port to serve the API, when running server.js
|
# PORT='3000' # Port to serve the API, when running server.js
|
||||||
# DISABLE_GUI='false' # Disable the GUI, and only serve the API
|
# DISABLE_GUI='false' # Disable the GUI, and only serve the API
|
||||||
# API_TIMEOUT_LIMIT='10000' # The timeout limit for API requests, in milliseconds
|
# API_TIMEOUT_LIMIT='10000' # The timeout limit for API requests, in milliseconds
|
||||||
# API_CORS_ORIGIN='*' # Enable CORS, by setting your allowed hostname(s) here
|
# API_CORS_ORIGIN='*' # Enable CORS, by setting your allowed hostname(s) here
|
||||||
# REACT_APP_API_ENDPOINT='/api' # The endpoint for the API (can be local or remote)
|
# API_ENABLE_RATE_LIMIT='true' # Enable rate limiting for the API
|
||||||
|
# REACT_APP_API_ENDPOINT='/api' # The endpoint for the API (can be local or remote)
|
||||||
|
|||||||
324
.github/README.md
vendored
324
.github/README.md
vendored
@@ -9,6 +9,22 @@
|
|||||||
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
---
|
||||||
|
<p align="center">
|
||||||
|
<sup>Kindly supported by:</sup><br>
|
||||||
|
<a href="https://terminaltrove.com/?utm_campaign=github&utm_medium=referral&utm_content=web-check&utm_source=wcgh">
|
||||||
|
<img src="https://i.ibb.co/8jrrcZ0/IMG-7210.jpg" width="300" alt="Terminal Trove">
|
||||||
|
<br>
|
||||||
|
<strong>The $HOME of all things in the terminal.</strong>
|
||||||
|
</a>
|
||||||
|
<br>
|
||||||
|
<a href="https://terminaltrove.com/newsletter?utm_campaign=github&utm_medium=referral&utm_content=web-check&utm_source=wcgh">
|
||||||
|
<sub>Find your next CLI / TUI tool and more at Terminal Trove,</sub>
|
||||||
|
<br>
|
||||||
|
<sup>Get updates on new tools on our newsletter.</sup>
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
#### Contents
|
#### Contents
|
||||||
@@ -66,17 +82,19 @@ Build & Deploys: [](https://github.com/Lissy93/web-check/actions/workflows/docker.yml)
|
[](https://github.com/Lissy93/web-check/actions/workflows/docker.yml)
|
||||||
[](https://github.com/Lissy93/web-check/actions/workflows/deploy-aws.yml)
|
[](https://github.com/Lissy93/web-check/actions/workflows/deploy-aws.yml)
|
||||||
<br />
|
<br />
|
||||||
Repo Managament & Miscellaneous: [](https://github.com/Lissy93/web-check/actions/workflows/mirror.yml)
|
Repo Management & Miscellaneous: [](https://github.com/Lissy93/web-check/actions/workflows/mirror.yml)
|
||||||
[](https://github.com/Lissy93/web-check/actions/workflows/credits.yml)
|
[](https://github.com/Lissy93/web-check/actions/workflows/credits.yml)
|
||||||
|
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
<details>
|
<details open>
|
||||||
<summary><h4>Expand to see all features</h4></summary>
|
<summary><b>Click to expand / collapse section</b></summary>
|
||||||
|
|
||||||
<sup>**Note** _this list needs updating, many more jobs have been added since..._</sup>
|
<sup>**Note** _this list needs updating, many more jobs have been added since..._</sup>
|
||||||
|
|
||||||
|
The following section outlines the core features, and briefly explains why this data might be useful for you to know, as well as linking to further resources for learning more.
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary><b>IP Info</b></summary>
|
<summary><b>IP Info</b></summary>
|
||||||
|
|
||||||
@@ -778,11 +796,11 @@ You can get the Docker image from:
|
|||||||
Install the prerequisites listed in the [Developing](#developing) section, then run:
|
Install the prerequisites listed in the [Developing](#developing) section, then run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/Lissy93/web-check.git # Grab the code
|
git clone https://github.com/Lissy93/web-check.git # Download the code from GitHub
|
||||||
cd web-check # Move into the project directory
|
cd web-check # Navigate into the project dir
|
||||||
yarn install # Install dependencies
|
yarn install # Install the NPM dependencies
|
||||||
yarn build # Build the app for production
|
yarn build # Build the app for production
|
||||||
yarn serve # Start the app (API and GUI)
|
yarn serve # Start the app (API and GUI)
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -821,10 +839,12 @@ Key | Value
|
|||||||
|
|
||||||
Key | Value
|
Key | Value
|
||||||
---|---
|
---|---
|
||||||
`CHROME_PATH` | The path the the Chromium executable (e.g. `/usr/bin/chromium`)
|
|
||||||
`PORT` | Port to serve the API, when running server.js (e.g. `3000`)
|
`PORT` | Port to serve the API, when running server.js (e.g. `3000`)
|
||||||
`DISABLE_GUI` | Disable the GUI, and only serve the API (e.g. `false`)
|
`API_ENABLE_RATE_LIMIT` | Enable rate-limiting for the /api endpoints (e.g. `true`)
|
||||||
`API_TIMEOUT_LIMIT` | The timeout limit for API requests, in milliseconds (e.g. `10000`)
|
`API_TIMEOUT_LIMIT` | The timeout limit for API requests, in milliseconds (e.g. `10000`)
|
||||||
|
`API_CORS_ORIGIN` | Enable CORS, by setting your allowed hostname(s) here (e.g. `example.com`)
|
||||||
|
`CHROME_PATH` | The path the Chromium executable (e.g. `/usr/bin/chromium`)
|
||||||
|
`DISABLE_GUI` | Disable the GUI, and only serve the API (e.g. `false`)
|
||||||
`REACT_APP_API_ENDPOINT` | The endpoint for the API, either local or remote (e.g. `/api`)
|
`REACT_APP_API_ENDPOINT` | The endpoint for the API, either local or remote (e.g. `/api`)
|
||||||
|
|
||||||
All values are optional.
|
All values are optional.
|
||||||
@@ -870,8 +890,9 @@ For bugs, please outline the steps needed to reproduce, and include relevant inf
|
|||||||
### Supporting
|
### Supporting
|
||||||
|
|
||||||
The app will remain 100% free and open source.
|
The app will remain 100% free and open source.
|
||||||
But due to the amount of traffic that the hosted instance gets, the lambda function usage is costing about $25/month. Any help with covering the costs via GitHub Sponsorship would be much appreciated. It's thanks to the support of the community that this project is able to be freely available for everyone :)
|
But due to the amount of traffic that the hosted instance gets, the lambda function usage is costing about $25/month.
|
||||||
|
Any help with covering the costs via GitHub Sponsorship would be much appreciated.
|
||||||
|
It's thanks to the support of the community that this project is able to be freely available for everyone :)
|
||||||
|
|
||||||
[](https://github.com/sponsors/Lissy93)
|
[](https://github.com/sponsors/Lissy93)
|
||||||
|
|
||||||
@@ -890,6 +911,13 @@ Credit to the following users for contributing to Web-Check
|
|||||||
<sub><b>Alicia Sykes</b></sub>
|
<sub><b>Alicia Sykes</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
<td align="center">
|
||||||
|
<a href="https://github.com/liss-bot">
|
||||||
|
<img src="https://avatars.githubusercontent.com/u/87835202?v=4" width="80;" alt="liss-bot"/>
|
||||||
|
<br />
|
||||||
|
<sub><b>Alicia Bot</b></sub>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
<td align="center">
|
<td align="center">
|
||||||
<a href="https://github.com/muni106">
|
<a href="https://github.com/muni106">
|
||||||
<img src="https://avatars.githubusercontent.com/u/65845442?v=4" width="80;" alt="muni106"/>
|
<img src="https://avatars.githubusercontent.com/u/65845442?v=4" width="80;" alt="muni106"/>
|
||||||
@@ -898,17 +926,89 @@ Credit to the following users for contributing to Web-Check
|
|||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td align="center">
|
<td align="center">
|
||||||
<a href="https://github.com/JinnaBalu">
|
<a href="https://github.com/ChrisCarini">
|
||||||
<img src="https://avatars.githubusercontent.com/u/11784253?v=4" width="80;" alt="JinnaBalu"/>
|
<img src="https://avatars.githubusercontent.com/u/6374067?v=4" width="80;" alt="ChrisCarini"/>
|
||||||
<br />
|
<br />
|
||||||
<sub><b>Jinna Balu</b></sub>
|
<sub><b>Chris Carini</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td align="center">
|
<td align="center">
|
||||||
<a href="https://github.com/liss-bot">
|
<a href="https://github.com/brianteeman">
|
||||||
<img src="https://avatars.githubusercontent.com/u/87835202?v=4" width="80;" alt="liss-bot"/>
|
<img src="https://avatars.githubusercontent.com/u/1296369?v=4" width="80;" alt="brianteeman"/>
|
||||||
<br />
|
<br />
|
||||||
<sub><b>Alicia Bot</b></sub>
|
<sub><b>Brian Teeman</b></sub>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align="center">
|
||||||
|
<a href="https://github.com/GreyXor">
|
||||||
|
<img src="https://avatars.githubusercontent.com/u/79602273?v=4" width="80;" alt="GreyXor"/>
|
||||||
|
<br />
|
||||||
|
<sub><b>GreyXor</b></sub>
|
||||||
|
</a>
|
||||||
|
</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center">
|
||||||
|
<a href="https://github.com/jinnabaalu">
|
||||||
|
<img src="https://avatars.githubusercontent.com/u/11784253?v=4" width="80;" alt="jinnabaalu"/>
|
||||||
|
<br />
|
||||||
|
<sub><b>Jinna Baalu</b></sub>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align="center">
|
||||||
|
<a href="https://github.com/bolens">
|
||||||
|
<img src="https://avatars.githubusercontent.com/u/1218380?v=4" width="80;" alt="bolens"/>
|
||||||
|
<br />
|
||||||
|
<sub><b>Michael Bolens</b></sub>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align="center">
|
||||||
|
<a href="https://github.com/robinson">
|
||||||
|
<img src="https://avatars.githubusercontent.com/u/237874?v=4" width="80;" alt="robinson"/>
|
||||||
|
<br />
|
||||||
|
<sub><b>Lth</b></sub>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align="center">
|
||||||
|
<a href="https://github.com/abhishekMuge">
|
||||||
|
<img src="https://avatars.githubusercontent.com/u/49590582?v=4" width="80;" alt="abhishekMuge"/>
|
||||||
|
<br />
|
||||||
|
<sub><b>Abhishek Muge</b></sub>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align="center">
|
||||||
|
<a href="https://github.com/UlisesGascon">
|
||||||
|
<img src="https://avatars.githubusercontent.com/u/5110813?v=4" width="80;" alt="UlisesGascon"/>
|
||||||
|
<br />
|
||||||
|
<sub><b>Ulises Gascón</b></sub>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align="center">
|
||||||
|
<a href="https://github.com/PhiRequiem">
|
||||||
|
<img src="https://avatars.githubusercontent.com/u/1323576?v=4" width="80;" alt="PhiRequiem"/>
|
||||||
|
<br />
|
||||||
|
<sub><b>PhiRequiem</b></sub>
|
||||||
|
</a>
|
||||||
|
</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center">
|
||||||
|
<a href="https://github.com/Myzel394">
|
||||||
|
<img src="https://avatars.githubusercontent.com/u/50424412?v=4" width="80;" alt="Myzel394"/>
|
||||||
|
<br />
|
||||||
|
<sub><b>Myzel394</b></sub>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align="center">
|
||||||
|
<a href="https://github.com/murrple-1">
|
||||||
|
<img src="https://avatars.githubusercontent.com/u/5559656?v=4" width="80;" alt="murrple-1"/>
|
||||||
|
<br />
|
||||||
|
<sub><b>Murray Christopherson</b></sub>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align="center">
|
||||||
|
<a href="https://github.com/t3chn0m4g3">
|
||||||
|
<img src="https://avatars.githubusercontent.com/u/4318452?v=4" width="80;" alt="t3chn0m4g3"/>
|
||||||
|
<br />
|
||||||
|
<sub><b>Marco Ochse</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td align="center">
|
<td align="center">
|
||||||
@@ -919,18 +1019,32 @@ Credit to the following users for contributing to Web-Check
|
|||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td align="center">
|
<td align="center">
|
||||||
<a href="https://github.com/UlisesGascon">
|
<a href="https://github.com/eltociear">
|
||||||
<img src="https://avatars.githubusercontent.com/u/5110813?v=4" width="80;" alt="UlisesGascon"/>
|
<img src="https://avatars.githubusercontent.com/u/22633385?v=4" width="80;" alt="eltociear"/>
|
||||||
<br />
|
<br />
|
||||||
<sub><b>Ulises Gascón</b></sub>
|
<sub><b>Ikko Eltociear Ashimine</b></sub>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align="center">
|
||||||
|
<a href="https://github.com/Gertje823">
|
||||||
|
<img src="https://avatars.githubusercontent.com/u/36937387?v=4" width="80;" alt="Gertje823"/>
|
||||||
|
<br />
|
||||||
|
<sub><b>Gertje823</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td></tr>
|
</td></tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td align="center">
|
<td align="center">
|
||||||
<a href="https://github.com/abhishekMuge">
|
<a href="https://github.com/epreston">
|
||||||
<img src="https://avatars.githubusercontent.com/u/49590582?v=4" width="80;" alt="abhishekMuge"/>
|
<img src="https://avatars.githubusercontent.com/u/347224?v=4" width="80;" alt="epreston"/>
|
||||||
<br />
|
<br />
|
||||||
<sub><b>Abhishek Muge</b></sub>
|
<sub><b>Ed Preston</b></sub>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align="center">
|
||||||
|
<a href="https://github.com/0xflotus">
|
||||||
|
<img src="https://avatars.githubusercontent.com/u/26602940?v=4" width="80;" alt="0xflotus"/>
|
||||||
|
<br />
|
||||||
|
<sub><b>0xflotus</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td></tr>
|
</td></tr>
|
||||||
</table>
|
</table>
|
||||||
@@ -943,6 +1057,34 @@ Huge thanks to these wonderful people, who sponsor me on GitHub, their support h
|
|||||||
<!-- readme: sponsors -start -->
|
<!-- readme: sponsors -start -->
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
|
<td align="center">
|
||||||
|
<a href="https://github.com/github">
|
||||||
|
<img src="https://avatars.githubusercontent.com/u/9919?v=4" width="80;" alt="github"/>
|
||||||
|
<br />
|
||||||
|
<sub><b>GitHub</b></sub>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align="center">
|
||||||
|
<a href="https://github.com/koconder">
|
||||||
|
<img src="https://avatars.githubusercontent.com/u/25068?u=582657b23622aaa3dfe68bd028a780f272f456fa&v=4" width="80;" alt="koconder"/>
|
||||||
|
<br />
|
||||||
|
<sub><b>Vincent Koc</b></sub>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align="center">
|
||||||
|
<a href="https://github.com/Admonstrator">
|
||||||
|
<img src="https://avatars.githubusercontent.com/u/69824?u=1e226d7a36cdd661c3e4cd486fea140d045b7d57&v=4" width="80;" alt="Admonstrator"/>
|
||||||
|
<br />
|
||||||
|
<sub><b>Aaron Viehl</b></sub>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align="center">
|
||||||
|
<a href="https://github.com/tbjers">
|
||||||
|
<img src="https://avatars.githubusercontent.com/u/1117052?v=4" width="80;" alt="tbjers"/>
|
||||||
|
<br />
|
||||||
|
<sub><b>Torgny Bjers</b></sub>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
<td align="center">
|
<td align="center">
|
||||||
<a href="https://github.com/emlazzarin">
|
<a href="https://github.com/emlazzarin">
|
||||||
<img src="https://avatars.githubusercontent.com/u/1141361?u=714e3487a3f2e0df721b01a0133945f075d3ff68&v=4" width="80;" alt="emlazzarin"/>
|
<img src="https://avatars.githubusercontent.com/u/1141361?u=714e3487a3f2e0df721b01a0133945f075d3ff68&v=4" width="80;" alt="emlazzarin"/>
|
||||||
@@ -952,11 +1094,12 @@ Huge thanks to these wonderful people, who sponsor me on GitHub, their support h
|
|||||||
</td>
|
</td>
|
||||||
<td align="center">
|
<td align="center">
|
||||||
<a href="https://github.com/AnandChowdhary">
|
<a href="https://github.com/AnandChowdhary">
|
||||||
<img src="https://avatars.githubusercontent.com/u/2841780?u=ca8e292b15abcc6cddaeae0abded0115c51b4789&v=4" width="80;" alt="AnandChowdhary"/>
|
<img src="https://avatars.githubusercontent.com/u/2841780?u=747e554b3a7f12eb20b7910e1c87d817844f714f&v=4" width="80;" alt="AnandChowdhary"/>
|
||||||
<br />
|
<br />
|
||||||
<sub><b>Anand Chowdhary</b></sub>
|
<sub><b>Anand Chowdhary</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td></tr>
|
||||||
|
<tr>
|
||||||
<td align="center">
|
<td align="center">
|
||||||
<a href="https://github.com/shrippen">
|
<a href="https://github.com/shrippen">
|
||||||
<img src="https://avatars.githubusercontent.com/u/2873570?v=4" width="80;" alt="shrippen"/>
|
<img src="https://avatars.githubusercontent.com/u/2873570?v=4" width="80;" alt="shrippen"/>
|
||||||
@@ -964,28 +1107,13 @@ Huge thanks to these wonderful people, who sponsor me on GitHub, their support h
|
|||||||
<sub><b>Shrippen</b></sub>
|
<sub><b>Shrippen</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td align="center">
|
|
||||||
<a href="https://github.com/davidpaulyoung">
|
|
||||||
<img src="https://avatars.githubusercontent.com/u/3418369?v=4" width="80;" alt="davidpaulyoung"/>
|
|
||||||
<br />
|
|
||||||
<sub><b>David Young</b></sub>
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
<td align="center">
|
|
||||||
<a href="https://github.com/k-rol">
|
|
||||||
<img src="https://avatars.githubusercontent.com/u/4050412?u=1162510eec7b7aeb31d4c7c65d51d4f773d823b0&v=4" width="80;" alt="k-rol"/>
|
|
||||||
<br />
|
|
||||||
<sub><b>Carol Ouellet</b></sub>
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
<td align="center">
|
<td align="center">
|
||||||
<a href="https://github.com/bile0026">
|
<a href="https://github.com/bile0026">
|
||||||
<img src="https://avatars.githubusercontent.com/u/5022496?u=aec96ad173c0ea9baaba93807efa8a848af6595c&v=4" width="80;" alt="bile0026"/>
|
<img src="https://avatars.githubusercontent.com/u/5022496?u=aec96ad173c0ea9baaba93807efa8a848af6595c&v=4" width="80;" alt="bile0026"/>
|
||||||
<br />
|
<br />
|
||||||
<sub><b>Zach Biles</b></sub>
|
<sub><b>Zach Biles</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td></tr>
|
</td>
|
||||||
<tr>
|
|
||||||
<td align="center">
|
<td align="center">
|
||||||
<a href="https://github.com/UlisesGascon">
|
<a href="https://github.com/UlisesGascon">
|
||||||
<img src="https://avatars.githubusercontent.com/u/5110813?u=3c41facd8aa26154b9451de237c34b0f78d672a5&v=4" width="80;" alt="UlisesGascon"/>
|
<img src="https://avatars.githubusercontent.com/u/5110813?u=3c41facd8aa26154b9451de237c34b0f78d672a5&v=4" width="80;" alt="UlisesGascon"/>
|
||||||
@@ -995,11 +1123,26 @@ Huge thanks to these wonderful people, who sponsor me on GitHub, their support h
|
|||||||
</td>
|
</td>
|
||||||
<td align="center">
|
<td align="center">
|
||||||
<a href="https://github.com/digitalarche">
|
<a href="https://github.com/digitalarche">
|
||||||
<img src="https://avatars.githubusercontent.com/u/6546135?u=a1a724d38ee1eba2d2d315495d482256312affe8&v=4" width="80;" alt="digitalarche"/>
|
<img src="https://avatars.githubusercontent.com/u/6546135?u=564756d7f44ab2206819eb3148f6d822673f5066&v=4" width="80;" alt="digitalarche"/>
|
||||||
<br />
|
<br />
|
||||||
<sub><b>Digital Archeology</b></sub>
|
<sub><b>Digital Archeology</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
<td align="center">
|
||||||
|
<a href="https://github.com/InDieTasten">
|
||||||
|
<img src="https://avatars.githubusercontent.com/u/7047377?u=8d8f8017628b38bc46dcbf3620e194b01d3fb2d1&v=4" width="80;" alt="InDieTasten"/>
|
||||||
|
<br />
|
||||||
|
<sub><b>InDieTasten</b></sub>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align="center">
|
||||||
|
<a href="https://github.com/araguaci">
|
||||||
|
<img src="https://avatars.githubusercontent.com/u/7318668?v=4" width="80;" alt="araguaci"/>
|
||||||
|
<br />
|
||||||
|
<sub><b>Araguaci</b></sub>
|
||||||
|
</a>
|
||||||
|
</td></tr>
|
||||||
|
<tr>
|
||||||
<td align="center">
|
<td align="center">
|
||||||
<a href="https://github.com/bmcgonag">
|
<a href="https://github.com/bmcgonag">
|
||||||
<img src="https://avatars.githubusercontent.com/u/7346620?u=2a0f9284f3e12ac1cc15288c254d1ec68a5081e8&v=4" width="80;" alt="bmcgonag"/>
|
<img src="https://avatars.githubusercontent.com/u/7346620?u=2a0f9284f3e12ac1cc15288c254d1ec68a5081e8&v=4" width="80;" alt="bmcgonag"/>
|
||||||
@@ -1015,39 +1158,103 @@ Huge thanks to these wonderful people, who sponsor me on GitHub, their support h
|
|||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td align="center">
|
<td align="center">
|
||||||
<a href="https://github.com/iJasonWade">
|
<a href="https://github.com/helixzz">
|
||||||
<img src="https://avatars.githubusercontent.com/u/12824479?u=5446c46f50a3197b9cd970e1669ed42e654c66b1&v=4" width="80;" alt="iJasonWade"/>
|
<img src="https://avatars.githubusercontent.com/u/12218889?u=d06d0c103dfbdb99450623064f7da3c5a3675fb6&v=4" width="80;" alt="helixzz"/>
|
||||||
<br />
|
<br />
|
||||||
<sub><b>Jason Ash</b></sub>
|
<sub><b>HeliXZz</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td align="center">
|
<td align="center">
|
||||||
<a href="https://github.com/DRXAquosus">
|
<a href="https://github.com/patvdv">
|
||||||
<img src="https://avatars.githubusercontent.com/u/45409262?v=4" width="80;" alt="DRXAquosus"/>
|
<img src="https://avatars.githubusercontent.com/u/12430107?u=e8911c2fb91af4d30432f76da8c40927b2830bd7&v=4" width="80;" alt="patvdv"/>
|
||||||
<br />
|
<br />
|
||||||
<sub><b>DRXAquosus</b></sub>
|
<sub><b>Patrick Van Der Veken</b></sub>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align="center">
|
||||||
|
<a href="https://github.com/plgonzalezrx8">
|
||||||
|
<img src="https://avatars.githubusercontent.com/u/19900049?u=48a58d2da520a9d712184c6e6e99927ff3cbf179&v=4" width="80;" alt="plgonzalezrx8"/>
|
||||||
|
<br />
|
||||||
|
<sub><b>Pedro Gonzalez</b></sub>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align="center">
|
||||||
|
<a href="https://github.com/mryesiller">
|
||||||
|
<img src="https://avatars.githubusercontent.com/u/24632172?u=0d20f2d615158f87cd60a3398d3efb026c32f291&v=4" width="80;" alt="mryesiller"/>
|
||||||
|
<br />
|
||||||
|
<sub><b>Göksel Yeşiller</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td></tr>
|
</td></tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
<td align="center">
|
||||||
|
<a href="https://github.com/allesauseinerhand">
|
||||||
|
<img src="https://avatars.githubusercontent.com/u/32039836?v=4" width="80;" alt="allesauseinerhand"/>
|
||||||
|
<br />
|
||||||
|
<sub><b>Allesauseinerhand</b></sub>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align="center">
|
||||||
|
<a href="https://github.com/forwardemail">
|
||||||
|
<img src="https://avatars.githubusercontent.com/u/32481436?v=4" width="80;" alt="forwardemail"/>
|
||||||
|
<br />
|
||||||
|
<sub><b>Forward Email - Open-source & Privacy-focused Email Service (2023)</b></sub>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align="center">
|
||||||
|
<a href="https://github.com/lamtrinhdev">
|
||||||
|
<img src="https://avatars.githubusercontent.com/u/49742151?u=c5eaca5aa6841a80605cf4f7d0e861a9e6339ef3&v=4" width="80;" alt="lamtrinhdev"/>
|
||||||
|
<br />
|
||||||
|
<sub><b>LamTrinh.Dev</b></sub>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
<td align="center">
|
<td align="center">
|
||||||
<a href="https://github.com/Bastii717">
|
<a href="https://github.com/Bastii717">
|
||||||
<img src="https://avatars.githubusercontent.com/u/53431819?u=dff9e241e6dbecbc283ee13486a2312cb3dd9784&v=4" width="80;" alt="Bastii717"/>
|
<img src="https://avatars.githubusercontent.com/u/53431819?u=604977bed6ad6875ada890d0d3765a4cacc2fa14&v=4" width="80;" alt="Bastii717"/>
|
||||||
<br />
|
<br />
|
||||||
<sub><b>Bastii717</b></sub>
|
<sub><b>Bastii717</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td align="center">
|
<td align="center">
|
||||||
<a href="https://github.com/ratty222">
|
<a href="https://github.com/getumbrel">
|
||||||
<img src="https://avatars.githubusercontent.com/u/92832598?u=137b65530cbd5f5af9c24cde51baa6cc77cc934b&v=4" width="80;" alt="ratty222"/>
|
<img src="https://avatars.githubusercontent.com/u/59408891?v=4" width="80;" alt="getumbrel"/>
|
||||||
<br />
|
<br />
|
||||||
<sub><b>Brent</b></sub>
|
<sub><b>Umbrel</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td align="center">
|
<td align="center">
|
||||||
<a href="https://github.com/jtfinley72">
|
<a href="https://github.com/M2TD">
|
||||||
<img src="https://avatars.githubusercontent.com/u/96497997?v=4" width="80;" alt="jtfinley72"/>
|
<img src="https://avatars.githubusercontent.com/u/85460457?v=4" width="80;" alt="M2TD"/>
|
||||||
<br />
|
<br />
|
||||||
<sub><b>Jtfinley72</b></sub>
|
<sub><b>M2TD</b></sub>
|
||||||
|
</a>
|
||||||
|
</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center">
|
||||||
|
<a href="https://github.com/frankdez93">
|
||||||
|
<img src="https://avatars.githubusercontent.com/u/87549420?v=4" width="80;" alt="frankdez93"/>
|
||||||
|
<br />
|
||||||
|
<sub><b>Frankdez93</b></sub>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align="center">
|
||||||
|
<a href="https://github.com/terminaltrove">
|
||||||
|
<img src="https://avatars.githubusercontent.com/u/121595180?v=4" width="80;" alt="terminaltrove"/>
|
||||||
|
<br />
|
||||||
|
<sub><b>Terminal Trove</b></sub>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align="center">
|
||||||
|
<a href="https://github.com/NixyJuppie">
|
||||||
|
<img src="https://avatars.githubusercontent.com/u/138570196?u=b102c222487905728b858704962d32759df29ebe&v=4" width="80;" alt="NixyJuppie"/>
|
||||||
|
<br />
|
||||||
|
<sub><b>Nixy</b></sub>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align="center">
|
||||||
|
<a href="https://github.com/nrvo">
|
||||||
|
<img src="https://avatars.githubusercontent.com/u/151435968?u=e1dcb307fd0efdc45cddbe9490a7b956e4da6835&v=4" width="80;" alt="nrvo"/>
|
||||||
|
<br />
|
||||||
|
<sub><b>Nrvo</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td></tr>
|
</td></tr>
|
||||||
</table>
|
</table>
|
||||||
@@ -1085,8 +1292,11 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|||||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
[](https://app.fossa.com/projects/git%2Bgithub.com%2FLissy93%2Fweb-check?ref=badge_large&issueType=license)
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
|
||||||
<!-- License + Copyright -->
|
<!-- License + Copyright -->
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<i>© <a href="https://aliciasykes.com">Alicia Sykes</a> 2023</i><br>
|
<i>© <a href="https://aliciasykes.com">Alicia Sykes</a> 2023</i><br>
|
||||||
@@ -1095,7 +1305,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||||||
<sup>Thanks for visiting :)</sup>
|
<sup>Thanks for visiting :)</sup>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<!-- Dinosaur -->
|
<!-- Dinosaurs are Awesome -->
|
||||||
<!--
|
<!--
|
||||||
. - ~ ~ ~ - .
|
. - ~ ~ ~ - .
|
||||||
.. _ .-~ ~-.
|
.. _ .-~ ~-.
|
||||||
|
|||||||
2
.github/workflows/docker.yml
vendored
2
.github/workflows/docker.yml
vendored
@@ -67,7 +67,7 @@ jobs:
|
|||||||
context: .
|
context: .
|
||||||
file: ./Dockerfile
|
file: ./Dockerfile
|
||||||
push: true
|
push: true
|
||||||
platforms: linux/amd64
|
platforms: linux/amd64,linux/arm64/v8
|
||||||
tags: |
|
tags: |
|
||||||
${{ env.GHCR_TAG }}
|
${{ env.GHCR_TAG }}
|
||||||
${{ env.DOCKERHUB_TAG }}
|
${{ env.DOCKERHUB_TAG }}
|
||||||
|
|||||||
26
Dockerfile
26
Dockerfile
@@ -5,7 +5,7 @@ ARG NODE_VERSION=16
|
|||||||
ARG DEBIAN_VERSION=bullseye
|
ARG DEBIAN_VERSION=bullseye
|
||||||
|
|
||||||
# Use Node.js Docker image as the base image, with specific Node and Debian versions
|
# Use Node.js Docker image as the base image, with specific Node and Debian versions
|
||||||
FROM docker.io/library/node:${NODE_VERSION}-${DEBIAN_VERSION}
|
FROM node:${NODE_VERSION}-${DEBIAN_VERSION} AS build
|
||||||
|
|
||||||
# Set the container's default shell to Bash and enable some options
|
# Set the container's default shell to Bash and enable some options
|
||||||
SHELL ["/bin/bash", "-euo", "pipefail", "-c"]
|
SHELL ["/bin/bash", "-euo", "pipefail", "-c"]
|
||||||
@@ -16,7 +16,7 @@ RUN apt-get update -qq --fix-missing && \
|
|||||||
wget --quiet --output-document=- https://dl-ssl.google.com/linux/linux_signing_key.pub | gpg --dearmor > /etc/apt/trusted.gpg.d/google-archive.gpg && \
|
wget --quiet --output-document=- https://dl-ssl.google.com/linux/linux_signing_key.pub | gpg --dearmor > /etc/apt/trusted.gpg.d/google-archive.gpg && \
|
||||||
echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google.list && \
|
echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google.list && \
|
||||||
apt-get update -qq && \
|
apt-get update -qq && \
|
||||||
apt-get -qqy --no-install-recommends install chromium traceroute && \
|
apt-get -qqy --no-install-recommends install chromium traceroute python make g++ && \
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Run the Chromium browser's version command and redirect its output to the /etc/chromium-version file
|
# Run the Chromium browser's version command and redirect its output to the /etc/chromium-version file
|
||||||
@@ -29,14 +29,28 @@ WORKDIR /app
|
|||||||
COPY package.json yarn.lock ./
|
COPY package.json yarn.lock ./
|
||||||
|
|
||||||
# Run yarn install to install dependencies and clear yarn cache
|
# Run yarn install to install dependencies and clear yarn cache
|
||||||
RUN yarn install && rm -rf /app/node_modules/.cache
|
RUN apt-get update && \
|
||||||
|
yarn install --production --frozen-lockfile --network-timeout 100000 && \
|
||||||
|
rm -rf /app/node_modules/.cache
|
||||||
|
|
||||||
# Copy all files to working directory
|
# Copy all files to working directory
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN mkdir /app/data
|
|
||||||
|
|
||||||
# Run yarn build to build the application
|
# Run yarn build to build the application
|
||||||
RUN yarn build
|
RUN yarn build --production
|
||||||
|
|
||||||
|
# Final stage
|
||||||
|
FROM node:${NODE_VERSION}-${DEBIAN_VERSION} AS final
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY package.json yarn.lock ./
|
||||||
|
COPY --from=build /app .
|
||||||
|
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y --no-install-recommends chromium traceroute && \
|
||||||
|
chmod 755 /usr/bin/chromium && \
|
||||||
|
rm -rf /var/lib/apt/lists/* /app/node_modules/.cache
|
||||||
|
|
||||||
# Exposed container port, the default is 3000, which can be modified through the environment variable PORT
|
# Exposed container port, the default is 3000, which can be modified through the environment variable PORT
|
||||||
EXPOSE ${PORT:-3000}
|
EXPOSE ${PORT:-3000}
|
||||||
@@ -45,4 +59,4 @@ EXPOSE ${PORT:-3000}
|
|||||||
ENV CHROME_PATH='/usr/bin/chromium'
|
ENV CHROME_PATH='/usr/bin/chromium'
|
||||||
|
|
||||||
# Define the command executed when the container starts and start the server.js of the Node.js application
|
# Define the command executed when the container starts and start the server.js of the Node.js application
|
||||||
CMD [ "node", "server.js" ]
|
CMD ["yarn", "serve"]
|
||||||
@@ -2,13 +2,47 @@ const normalizeUrl = (url) => {
|
|||||||
return url.startsWith('http') ? url : `https://${url}`;
|
return url.startsWith('http') ? url : `https://${url}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// If present, set a shorter timeout for API requests
|
||||||
|
const TIMEOUT = process.env.API_TIMEOUT_LIMIT ? parseInt(process.env.API_TIMEOUT_LIMIT, 10) : 60000;
|
||||||
|
|
||||||
|
// If present, set CORS allowed origins for responses
|
||||||
|
const ALLOWED_ORIGINS = process.env.API_CORS_ORIGIN || '*';
|
||||||
|
|
||||||
|
// Set the platform currently being used
|
||||||
|
let PLATFORM = 'NETLIFY';
|
||||||
|
if (process.env.PLATFORM) { PLATFORM = process.env.PLATFORM.toUpperCase(); }
|
||||||
|
else if (process.env.VERCEL) { PLATFORM = 'VERCEL'; }
|
||||||
|
else if (process.env.WC_SERVER) { PLATFORM = 'NODE'; }
|
||||||
|
|
||||||
|
// Define the headers to be returned with each response
|
||||||
const headers = {
|
const headers = {
|
||||||
'Access-Control-Allow-Origin': process.env.API_CORS_ORIGIN || '*',
|
'Access-Control-Allow-Origin': ALLOWED_ORIGINS,
|
||||||
'Access-Control-Allow-Credentials': true,
|
'Access-Control-Allow-Credentials': true,
|
||||||
'Content-Type': 'application/json;charset=UTF-8',
|
'Content-Type': 'application/json;charset=UTF-8',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const timeoutErrorMsg = 'You can re-trigger this request, by clicking "Retry"\n'
|
||||||
|
+ 'If you\'re running your own instance of Web Check, then you can '
|
||||||
|
+ 'resolve this issue, by increasing the timeout limit in the '
|
||||||
|
+ '`API_TIMEOUT_LIMIT` environmental variable to a higher value (in milliseconds), '
|
||||||
|
+ 'or if you\'re hosting on Vercel increase the maxDuration in vercel.json.\n\n'
|
||||||
|
+ `The public instance currently has a lower timeout of ${TIMEOUT}ms `
|
||||||
|
+ 'in order to keep running costs affordable, so that Web Check can '
|
||||||
|
+ 'remain freely available for everyone.';
|
||||||
|
|
||||||
|
// A middleware function used by all API routes on all platforms
|
||||||
const commonMiddleware = (handler) => {
|
const commonMiddleware = (handler) => {
|
||||||
|
|
||||||
|
// Create a timeout promise, to throw an error if a request takes too long
|
||||||
|
const createTimeoutPromise = (timeoutMs) => {
|
||||||
|
return new Promise((_, reject) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
reject(new Error(`Request timed-out after ${timeoutMs} ms`));
|
||||||
|
}, timeoutMs);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// Vercel
|
// Vercel
|
||||||
const vercelHandler = async (request, response) => {
|
const vercelHandler = async (request, response) => {
|
||||||
const queryParams = request.query || {};
|
const queryParams = request.query || {};
|
||||||
@@ -21,7 +55,12 @@ const commonMiddleware = (handler) => {
|
|||||||
const url = normalizeUrl(rawUrl);
|
const url = normalizeUrl(rawUrl);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const handlerResponse = await handler(url, request);
|
// Race the handler against the timeout
|
||||||
|
const handlerResponse = await Promise.race([
|
||||||
|
handler(url, request),
|
||||||
|
createTimeoutPromise(TIMEOUT)
|
||||||
|
]);
|
||||||
|
|
||||||
if (handlerResponse.body && handlerResponse.statusCode) {
|
if (handlerResponse.body && handlerResponse.statusCode) {
|
||||||
response.status(handlerResponse.statusCode).json(handlerResponse.body);
|
response.status(handlerResponse.statusCode).json(handlerResponse.body);
|
||||||
} else {
|
} else {
|
||||||
@@ -30,7 +69,12 @@ const commonMiddleware = (handler) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
response.status(500).json({ error: error.message });
|
let errorCode = 500;
|
||||||
|
if (error.message.includes('timed-out') || response.statusCode === 504) {
|
||||||
|
errorCode = 408;
|
||||||
|
error.message = `${error.message}\n\n${timeoutErrorMsg}`;
|
||||||
|
}
|
||||||
|
response.status(errorCode).json({ error: error.message });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -51,7 +95,12 @@ const commonMiddleware = (handler) => {
|
|||||||
const url = normalizeUrl(rawUrl);
|
const url = normalizeUrl(rawUrl);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const handlerResponse = await handler(url, event, context);
|
// Race the handler against the timeout
|
||||||
|
const handlerResponse = await Promise.race([
|
||||||
|
handler(url, event, context),
|
||||||
|
createTimeoutPromise(TIMEOUT)
|
||||||
|
]);
|
||||||
|
|
||||||
if (handlerResponse.body && handlerResponse.statusCode) {
|
if (handlerResponse.body && handlerResponse.statusCode) {
|
||||||
callback(null, handlerResponse);
|
callback(null, handlerResponse);
|
||||||
} else {
|
} else {
|
||||||
@@ -71,11 +120,7 @@ const commonMiddleware = (handler) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// The format of the handlers varies between platforms
|
// The format of the handlers varies between platforms
|
||||||
// E.g. Netlify + AWS expect Lambda functions, but Vercel or Node needs standard handler
|
const nativeMode = (['VERCEL', 'NODE'].includes(PLATFORM));
|
||||||
const platformEnv = (process.env.PLATFORM || '').toUpperCase(); // Has user set platform manually?
|
|
||||||
|
|
||||||
const nativeMode = (['VERCEL', 'NODE'].includes(platformEnv) || process.env.VERCEL || process.env.WC_SERVER);
|
|
||||||
|
|
||||||
return nativeMode ? vercelHandler : netlifyHandler;
|
return nativeMode ? vercelHandler : netlifyHandler;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,11 @@ const handler = async (domain) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
res.on('end', () => {
|
res.on('end', () => {
|
||||||
resolve(JSON.parse(data));
|
try {
|
||||||
|
resolve(JSON.parse(data));
|
||||||
|
} catch (error) {
|
||||||
|
reject(new Error('Invalid JSON response'));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
res.on('error', error => {
|
res.on('error', error => {
|
||||||
@@ -51,4 +55,3 @@ const handler = async (domain) => {
|
|||||||
|
|
||||||
module.exports = middleware(handler);
|
module.exports = middleware(handler);
|
||||||
module.exports.handler = middleware(handler);
|
module.exports.handler = middleware(handler);
|
||||||
|
|
||||||
|
|||||||
@@ -54,6 +54,11 @@ const handler = async (url, event, context) => {
|
|||||||
if (yahooMx.length > 0) {
|
if (yahooMx.length > 0) {
|
||||||
mailServices.push({ provider: 'Yahoo', value: yahooMx[0].exchange });
|
mailServices.push({ provider: 'Yahoo', value: yahooMx[0].exchange });
|
||||||
}
|
}
|
||||||
|
// Check MX records for Mimecast
|
||||||
|
const mimecastMx = mxRecords.filter(record => record.exchange.includes('mimecast.com'));
|
||||||
|
if (mimecastMx.length > 0) {
|
||||||
|
mailServices.push({ provider: 'Mimecast', value: mimecastMx[0].exchange });
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
mxRecords,
|
mxRecords,
|
||||||
|
|||||||
@@ -5,14 +5,17 @@ const handler = async (url, event, context) => {
|
|||||||
const apiKey = process.env.GOOGLE_CLOUD_API_KEY;
|
const apiKey = process.env.GOOGLE_CLOUD_API_KEY;
|
||||||
|
|
||||||
if (!apiKey) {
|
if (!apiKey) {
|
||||||
throw new Error('API key (GOOGLE_CLOUD_API_KEY) not set');
|
throw new Error(
|
||||||
|
'Missing Google API. You need to set the `GOOGLE_CLOUD_API_KEY` environment variable'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const endpoint = `https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url=${encodeURIComponent(url)}&category=PERFORMANCE&category=ACCESSIBILITY&category=BEST_PRACTICES&category=SEO&category=PWA&strategy=mobile&key=${apiKey}`;
|
const endpoint = `https://www.googleapis.com/pagespeedonline/v5/runPagespeed?`
|
||||||
|
+ `url=${encodeURIComponent(url)}&category=PERFORMANCE&category=ACCESSIBILITY`
|
||||||
|
+ `&category=BEST_PRACTICES&category=SEO&category=PWA&strategy=mobile`
|
||||||
|
+ `&key=${apiKey}`;
|
||||||
|
|
||||||
const response = await axios.get(endpoint);
|
return (await axios.get(endpoint)).data;
|
||||||
|
|
||||||
return response.data;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = middleware(handler);
|
module.exports = middleware(handler);
|
||||||
|
|||||||
@@ -6,15 +6,17 @@ const xml2js = require('xml2js');
|
|||||||
const handler = async (url) => {
|
const handler = async (url) => {
|
||||||
let sitemapUrl = `${url}/sitemap.xml`;
|
let sitemapUrl = `${url}/sitemap.xml`;
|
||||||
|
|
||||||
|
const hardTimeOut = 5000;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Try to fetch sitemap directly
|
// Try to fetch sitemap directly
|
||||||
let sitemapRes;
|
let sitemapRes;
|
||||||
try {
|
try {
|
||||||
sitemapRes = await axios.get(sitemapUrl, { timeout: 5000 });
|
sitemapRes = await axios.get(sitemapUrl, { timeout: hardTimeOut });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.status === 404) {
|
if (error.response && error.response.status === 404) {
|
||||||
// If sitemap not found, try to fetch it from robots.txt
|
// If sitemap not found, try to fetch it from robots.txt
|
||||||
const robotsRes = await axios.get(`${url}/robots.txt`, { timeout: 5000 });
|
const robotsRes = await axios.get(`${url}/robots.txt`, { timeout: hardTimeOut });
|
||||||
const robotsTxt = robotsRes.data.split('\n');
|
const robotsTxt = robotsRes.data.split('\n');
|
||||||
|
|
||||||
for (let line of robotsTxt) {
|
for (let line of robotsTxt) {
|
||||||
@@ -28,7 +30,7 @@ const handler = async (url) => {
|
|||||||
return { skipped: 'No sitemap found' };
|
return { skipped: 'No sitemap found' };
|
||||||
}
|
}
|
||||||
|
|
||||||
sitemapRes = await axios.get(sitemapUrl, { timeout: 5000 });
|
sitemapRes = await axios.get(sitemapUrl, { timeout: hardTimeOut });
|
||||||
} else {
|
} else {
|
||||||
throw error; // If other error, throw it
|
throw error; // If other error, throw it
|
||||||
}
|
}
|
||||||
@@ -39,10 +41,8 @@ const handler = async (url) => {
|
|||||||
|
|
||||||
return sitemap;
|
return sitemap;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// If error occurs
|
|
||||||
console.log(error.message);
|
|
||||||
if (error.code === 'ECONNABORTED') {
|
if (error.code === 'ECONNABORTED') {
|
||||||
return { error: 'Request timed out' };
|
return { error: `Request timed-out after ${hardTimeOut}ms` };
|
||||||
} else {
|
} else {
|
||||||
return { error: error.message };
|
return { error: error.message };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
publish = "build"
|
publish = "build"
|
||||||
functions = "api"
|
functions = "api"
|
||||||
|
|
||||||
# Environmental variables and optioanl secrets
|
# Environmental variables and optional secrets
|
||||||
[build.environment]
|
[build.environment]
|
||||||
# Build configuration env vars (uncomment if you want to conigure these)
|
# Build configuration env vars (uncomment if you want to conigure these)
|
||||||
# CI="false" # Set CI to false, to prevent warnings from exiting the build
|
# CI="false" # Set CI to false, to prevent warnings from exiting the build
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "web-check",
|
"name": "web-check",
|
||||||
"version": "1.0.0",
|
"version": "1.1.2",
|
||||||
"private": false,
|
"private": false,
|
||||||
"description": "All-in-one OSINT tool for analyzing any website",
|
"description": "All-in-one OSINT tool for analyzing any website",
|
||||||
"repository": "github:lissy93/web-check",
|
"repository": "github:lissy93/web-check",
|
||||||
@@ -45,6 +45,7 @@
|
|||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"csv-parser": "^3.0.0",
|
"csv-parser": "^3.0.0",
|
||||||
"dotenv": "^16.3.1",
|
"dotenv": "^16.3.1",
|
||||||
|
"express-rate-limit": "^7.2.0",
|
||||||
"flatted": "^3.2.7",
|
"flatted": "^3.2.7",
|
||||||
"follow-redirects": "^1.15.2",
|
"follow-redirects": "^1.15.2",
|
||||||
"got": "^13.0.0",
|
"got": "^13.0.0",
|
||||||
|
|||||||
@@ -20,6 +20,9 @@
|
|||||||
<meta property="og:image" content="/banner.png">
|
<meta property="og:image" content="/banner.png">
|
||||||
<meta property="og:url" content="https://web-check.xyz">
|
<meta property="og:url" content="https://web-check.xyz">
|
||||||
<meta name="twitter:card" content="summary_large_image">
|
<meta name="twitter:card" content="summary_large_image">
|
||||||
|
|
||||||
|
<!-- DarkReader -->
|
||||||
|
<meta name="darkreader-lock">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>
|
<noscript>
|
||||||
|
|||||||
30
server.js
30
server.js
@@ -2,6 +2,7 @@ const express = require('express');
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const cors = require('cors');
|
const cors = require('cors');
|
||||||
|
const rateLimit = require('express-rate-limit');
|
||||||
const historyApiFallback = require('connect-history-api-fallback');
|
const historyApiFallback = require('connect-history-api-fallback');
|
||||||
require('dotenv').config();
|
require('dotenv').config();
|
||||||
|
|
||||||
@@ -20,6 +21,34 @@ app.use(cors({
|
|||||||
origin: process.env.API_CORS_ORIGIN || '*',
|
origin: process.env.API_CORS_ORIGIN || '*',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// Define max requests within each time frame
|
||||||
|
const limits = [
|
||||||
|
{ timeFrame: 10 * 60, max: 100, messageTime: '10 minutes' },
|
||||||
|
{ timeFrame: 60 * 60, max: 250, messageTime: '1 hour' },
|
||||||
|
{ timeFrame: 12 * 60 * 60, max: 500, messageTime: '12 hours' },
|
||||||
|
];
|
||||||
|
|
||||||
|
// Construct a message to be returned if the user has been rate-limited
|
||||||
|
const makeLimiterResponseMsg = (retryAfter) => {
|
||||||
|
const why = 'This keeps the service running smoothly for everyone. '
|
||||||
|
+ 'You can get around these limits by running your own instance of Web Check.';
|
||||||
|
return `You've been rate-limited, please try again in ${retryAfter} seconds.\n${why}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create rate limiters for each time frame
|
||||||
|
const limiters = limits.map(limit => rateLimit({
|
||||||
|
windowMs: limit.timeFrame * 1000,
|
||||||
|
max: limit.max,
|
||||||
|
standardHeaders: true,
|
||||||
|
legacyHeaders: false,
|
||||||
|
message: { error: makeLimiterResponseMsg(limit.messageTime) }
|
||||||
|
}));
|
||||||
|
|
||||||
|
// If rate-limiting enabled, then apply the limiters to the /api endpoint
|
||||||
|
if (process.env.API_ENABLE_RATE_LIMIT === 'true') {
|
||||||
|
app.use('/api', limiters);
|
||||||
|
}
|
||||||
|
|
||||||
// Read and register each API function as an Express routes
|
// Read and register each API function as an Express routes
|
||||||
fs.readdirSync(dirPath, { withFileTypes: true })
|
fs.readdirSync(dirPath, { withFileTypes: true })
|
||||||
.filter(dirent => dirent.isFile() && dirent.name.endsWith('.js'))
|
.filter(dirent => dirent.isFile() && dirent.name.endsWith('.js'))
|
||||||
@@ -86,7 +115,6 @@ fs.readdirSync(dirPath, { withFileTypes: true })
|
|||||||
res.json(results);
|
res.json(results);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// Handle SPA routing
|
// Handle SPA routing
|
||||||
app.use(historyApiFallback({
|
app.use(historyApiFallback({
|
||||||
rewrites: [
|
rewrites: [
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ const Container = Styled.main`
|
|||||||
background: ${colors.background};
|
background: ${colors.background};
|
||||||
color: ${colors.textColor};
|
color: ${colors.textColor};
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: 100vh;
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ export const ExpandableRow = (props: RowProps) => {
|
|||||||
{ rowList?.map((row: RowProps, index: number) => {
|
{ rowList?.map((row: RowProps, index: number) => {
|
||||||
return (
|
return (
|
||||||
<SubRow key={`${row.lbl}-${index}`}>
|
<SubRow key={`${row.lbl}-${index}`}>
|
||||||
<span className="lbl" title={row.title}>{row.lbl}</span>
|
<span className="lbl" title={row.title?.toString()}>{row.lbl}</span>
|
||||||
<span className="val" title={row.val} onClick={() => copyToClipboard(row.val)}>
|
<span className="val" title={row.val} onClick={() => copyToClipboard(row.val)}>
|
||||||
{formatValue(row.val)}
|
{formatValue(row.val)}
|
||||||
</span>
|
</span>
|
||||||
@@ -199,7 +199,7 @@ const Row = (props: RowProps) => {
|
|||||||
if (children) return <StyledRow key={`${lbl}-${val}`}>{children}</StyledRow>;
|
if (children) return <StyledRow key={`${lbl}-${val}`}>{children}</StyledRow>;
|
||||||
return (
|
return (
|
||||||
<StyledRow key={`${lbl}-${val}`}>
|
<StyledRow key={`${lbl}-${val}`}>
|
||||||
{ lbl && <span className="lbl" title={title}>{lbl}</span> }
|
{ lbl && <span className="lbl" title={title?.toString()}>{lbl}</span> }
|
||||||
<span className="val" title={val} onClick={() => copyToClipboard(val)}>
|
<span className="val" title={val} onClick={() => copyToClipboard(val)}>
|
||||||
{formatValue(val)}
|
{formatValue(val)}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -6,11 +6,13 @@ const BlockListsCard = (props: {data: any, title: string, actionButtons: any }):
|
|||||||
const blockLists = props.data.blocklists;
|
const blockLists = props.data.blocklists;
|
||||||
return (
|
return (
|
||||||
<Card heading={props.title} actionButtons={props.actionButtons}>
|
<Card heading={props.title} actionButtons={props.actionButtons}>
|
||||||
{ blockLists.map((blocklist: any) => (
|
{ blockLists.map((blocklist: any, blockIndex: number) => (
|
||||||
<Row
|
<Row
|
||||||
title={blocklist.serverIp}
|
title={blocklist.serverIp}
|
||||||
lbl={blocklist.server}
|
lbl={blocklist.server}
|
||||||
val={blocklist.isBlocked ? '❌ Blocked' : '✅ Not Blocked'} />
|
val={blocklist.isBlocked ? '❌ Blocked' : '✅ Not Blocked'}
|
||||||
|
key={`blocklist-${blockIndex}-${blocklist.serverIp}`}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -18,12 +18,12 @@ const DnsServerCard = (props: {data: any, title: string, actionButtons: any }):
|
|||||||
return (
|
return (
|
||||||
<Card heading={props.title} actionButtons={props.actionButtons} styles={cardStyles}>
|
<Card heading={props.title} actionButtons={props.actionButtons} styles={cardStyles}>
|
||||||
{dnsSecurity.dns.map((dns: any, index: number) => {
|
{dnsSecurity.dns.map((dns: any, index: number) => {
|
||||||
return (<>
|
return (<div key={`dns-${index}`}>
|
||||||
{ dnsSecurity.dns.length > 1 && <Heading as="h4" size="small" color={colors.primary}>DNS Server #{index+1}</Heading> }
|
{ dnsSecurity.dns.length > 1 && <Heading as="h4" size="small" color={colors.primary}>DNS Server #{index+1}</Heading> }
|
||||||
<Row lbl="IP Address" val={dns.address} key={`ip-${index}`} />
|
<Row lbl="IP Address" val={dns.address} key={`ip-${index}`} />
|
||||||
{ dns.hostname && <Row lbl="Hostname" val={dns.hostname} key={`host-${index}`} /> }
|
{ dns.hostname && <Row lbl="Hostname" val={dns.hostname} key={`host-${index}`} /> }
|
||||||
<Row lbl="DoH Support" val={dns.dohDirectSupports ? '✅ Yes*' : '❌ No*'} key={`doh-${index}`} />
|
<Row lbl="DoH Support" val={dns.dohDirectSupports ? '✅ Yes*' : '❌ No*'} key={`doh-${index}`} />
|
||||||
</>);
|
</div>);
|
||||||
})}
|
})}
|
||||||
{dnsSecurity.dns.length > 0 && (<small>
|
{dnsSecurity.dns.length > 0 && (<small>
|
||||||
* DoH Support is determined by the DNS server's response to a DoH query.
|
* DoH Support is determined by the DNS server's response to a DoH query.
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ span.val {
|
|||||||
const ServerStatusCard = (props: { data: any, title: string, actionButtons: any }): JSX.Element => {
|
const ServerStatusCard = (props: { data: any, title: string, actionButtons: any }): JSX.Element => {
|
||||||
const serverStatus = props.data;
|
const serverStatus = props.data;
|
||||||
return (
|
return (
|
||||||
<Card heading={props.title} actionButtons={props.actionButtons} styles={cardStyles}>
|
<Card heading={props.title.toString()} actionButtons={props.actionButtons} styles={cardStyles}>
|
||||||
<Row lbl="" val="">
|
<Row lbl="" val="">
|
||||||
<span className="lbl">Is Up?</span>
|
<span className="lbl">Is Up?</span>
|
||||||
{ serverStatus.isUp ? <span className="val up">✅ Online</span> : <span className="val down">❌ Offline</span>}
|
{ serverStatus.isUp ? <span className="val up">✅ Online</span> : <span className="val down">❌ Offline</span>}
|
||||||
|
|||||||
@@ -90,7 +90,6 @@ const SslCertCard = (props: { data: any, title: string, actionButtons: any }): J
|
|||||||
{ valid_from && <DataRow lbl="Renewed" val={formatDate(valid_from)} /> }
|
{ valid_from && <DataRow lbl="Renewed" val={formatDate(valid_from)} /> }
|
||||||
{ serialNumber && <DataRow lbl="Serial Num" val={serialNumber} /> }
|
{ serialNumber && <DataRow lbl="Serial Num" val={serialNumber} /> }
|
||||||
{ fingerprint && <DataRow lbl="Fingerprint" val={fingerprint} /> }
|
{ fingerprint && <DataRow lbl="Fingerprint" val={fingerprint} /> }
|
||||||
{ fingerprint && <DataRow lbl="Fingerprint" val={fingerprint} /> }
|
|
||||||
{ ext_key_usage && <ListRow title="Extended Key Usage" list={getExtendedKeyUsage(ext_key_usage)} /> }
|
{ ext_key_usage && <ListRow title="Extended Key Usage" list={getExtendedKeyUsage(ext_key_usage)} /> }
|
||||||
|
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ const TlsCard = (props: {data: any, title: string, actionButtons: any }): JSX.El
|
|||||||
<Card heading={props.title} actionButtons={props.actionButtons}>
|
<Card heading={props.title} actionButtons={props.actionButtons}>
|
||||||
{ cipherSuites.length && cipherSuites.map((cipherSuite: any, index: number) => {
|
{ cipherSuites.length && cipherSuites.map((cipherSuite: any, index: number) => {
|
||||||
return (
|
return (
|
||||||
<ExpandableRow lbl={cipherSuite.title} val="" rowList={cipherSuite.fields} />
|
<ExpandableRow key={`tls-${index}`} lbl={cipherSuite.title} val="" rowList={cipherSuite.fields} />
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
{ !cipherSuites.length && (
|
{ !cipherSuites.length && (
|
||||||
|
|||||||
@@ -59,8 +59,15 @@ const TlsCard = (props: {data: any, title: string, actionButtons: any }): JSX.El
|
|||||||
const scanId = props.data?.id;
|
const scanId = props.data?.id;
|
||||||
return (
|
return (
|
||||||
<Card heading={props.title} actionButtons={props.actionButtons}>
|
<Card heading={props.title} actionButtons={props.actionButtons}>
|
||||||
{clientSupport.map((support: any) => {
|
{clientSupport.map((support: any, index: number) => {
|
||||||
return (<ExpandableRow lbl={support.title} val={support.value || '?'} rowList={support.fields} />)
|
return (
|
||||||
|
<ExpandableRow
|
||||||
|
key={`tls-client-${index}`}
|
||||||
|
lbl={support.title}
|
||||||
|
val={support.value || '?'}
|
||||||
|
rowList={support.fields}
|
||||||
|
/>
|
||||||
|
)
|
||||||
})}
|
})}
|
||||||
{ !clientSupport.length && (
|
{ !clientSupport.length && (
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -99,7 +99,13 @@ const TlsCard = (props: {data: any, title: string, actionButtons: any }): JSX.El
|
|||||||
<Card heading={props.title} actionButtons={props.actionButtons}>
|
<Card heading={props.title} actionButtons={props.actionButtons}>
|
||||||
{ tlsResults.length > 0 && tlsResults.map((row: any, index: number) => {
|
{ tlsResults.length > 0 && tlsResults.map((row: any, index: number) => {
|
||||||
return (
|
return (
|
||||||
<Row lbl={row.lbl} val={row.val} plaintext={row.plaintext} listResults={row.list} />
|
<Row
|
||||||
|
lbl={row.lbl}
|
||||||
|
val={row.val}
|
||||||
|
plaintext={row.plaintext}
|
||||||
|
listResults={row.list}
|
||||||
|
key={`tls-issues-${index}`}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
<Expandable>
|
<Expandable>
|
||||||
|
|||||||
@@ -92,75 +92,75 @@ const resources = [
|
|||||||
title: 'SSL Labs Test',
|
title: 'SSL Labs Test',
|
||||||
link: 'https://ssllabs.com/ssltest/analyze.html',
|
link: 'https://ssllabs.com/ssltest/analyze.html',
|
||||||
icon: 'https://i.ibb.co/6bVL8JK/Qualys-ssl-labs.png',
|
icon: 'https://i.ibb.co/6bVL8JK/Qualys-ssl-labs.png',
|
||||||
description: 'Analyzes the SSL configuration of a server and grades it.',
|
description: 'Analyzes the SSL configuration of a server and grades it',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Virus Total',
|
title: 'Virus Total',
|
||||||
link: 'https://virustotal.com',
|
link: 'https://virustotal.com',
|
||||||
icon: 'https://i.ibb.co/dWFz0RC/Virustotal.png',
|
icon: 'https://i.ibb.co/dWFz0RC/Virustotal.png',
|
||||||
description: 'Checks a URL against multiple antivirus engines.',
|
description: 'Checks a URL against multiple antivirus engines',
|
||||||
searchLink: 'https://www.virustotal.com/gui/domain/{URL}',
|
searchLink: 'https://www.virustotal.com/gui/domain/{URL}',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Shodan',
|
title: 'Shodan',
|
||||||
link: 'https://shodan.io/',
|
link: 'https://shodan.io/',
|
||||||
icon: 'https://i.ibb.co/SBZ8WG4/shodan.png',
|
icon: 'https://i.ibb.co/SBZ8WG4/shodan.png',
|
||||||
description: 'Search engine for Internet-connected devices.',
|
description: 'Search engine for Internet-connected devices',
|
||||||
searchLink: 'https://www.shodan.io/search/report?query={URL}',
|
searchLink: 'https://www.shodan.io/search/report?query={URL}',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Archive',
|
title: 'Archive',
|
||||||
link: 'https://archive.org/',
|
link: 'https://archive.org/',
|
||||||
icon: 'https://i.ibb.co/nfKMvCm/Archive-org.png',
|
icon: 'https://i.ibb.co/nfKMvCm/Archive-org.png',
|
||||||
description: 'View previous versions of a site via the Internet Archive.',
|
description: 'View previous versions of a site via the Internet Archive',
|
||||||
searchLink: 'https://web.archive.org/web/*/{URL}',
|
searchLink: 'https://web.archive.org/web/*/{URL}',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'URLScan',
|
title: 'URLScan',
|
||||||
link: 'https://urlscan.io/',
|
link: 'https://urlscan.io/',
|
||||||
icon: 'https://i.ibb.co/cYXt8SH/Url-scan.png',
|
icon: 'https://i.ibb.co/cYXt8SH/Url-scan.png',
|
||||||
description: 'Scans a URL and provides information about the page.',
|
description: 'Scans a URL and provides information about the page',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Sucuri SiteCheck',
|
title: 'Sucuri SiteCheck',
|
||||||
link: 'https://sitecheck.sucuri.net/',
|
link: 'https://sitecheck.sucuri.net/',
|
||||||
icon: 'https://i.ibb.co/K5pTP1K/Sucuri-site-check.png',
|
icon: 'https://i.ibb.co/K5pTP1K/Sucuri-site-check.png',
|
||||||
description: 'Checks a URL against blacklists and known threats.',
|
description: 'Checks a URL against blacklists and known threats',
|
||||||
searchLink: 'https://www.ssllabs.com/ssltest/analyze.html?d={URL}',
|
searchLink: 'https://www.ssllabs.com/ssltest/analyze.html?d={URL}',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Domain Tools',
|
title: 'Domain Tools',
|
||||||
link: 'https://whois.domaintools.com/',
|
link: 'https://whois.domaintools.com/',
|
||||||
icon: 'https://i.ibb.co/zJfCKjM/Domain-tools.png',
|
icon: 'https://i.ibb.co/zJfCKjM/Domain-tools.png',
|
||||||
description: 'Run a WhoIs lookup on a domain.',
|
description: 'Run a WhoIs lookup on a domain',
|
||||||
searchLink: 'https://whois.domaintools.com/{URL}',
|
searchLink: 'https://whois.domaintools.com/{URL}',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'NS Lookup',
|
title: 'NS Lookup',
|
||||||
link: 'https://nslookup.io/',
|
link: 'https://nslookup.io/',
|
||||||
icon: 'https://i.ibb.co/BLSWvBv/Ns-lookup.png',
|
icon: 'https://i.ibb.co/BLSWvBv/Ns-lookup.png',
|
||||||
description: 'View DNS records for a domain.',
|
description: 'View DNS records for a domain',
|
||||||
searchLink: 'https://www.nslookup.io/domains/{URL}/dns-records/',
|
searchLink: 'https://www.nslookup.io/domains/{URL}/dns-records/',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'DNS Checker',
|
title: 'DNS Checker',
|
||||||
link: 'https://dnschecker.org/',
|
link: 'https://dnschecker.org/',
|
||||||
icon: 'https://i.ibb.co/gyKtgZ1/Dns-checker.webp',
|
icon: 'https://i.ibb.co/gyKtgZ1/Dns-checker.webp',
|
||||||
description: 'Check global DNS propagation across multiple servers.',
|
description: 'Check global DNS propagation across multiple servers',
|
||||||
searchLink: 'https://dnschecker.org/#A/{URL}',
|
searchLink: 'https://dnschecker.org/#A/{URL}',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Censys',
|
title: 'Censys',
|
||||||
link: 'https://search.censys.io/',
|
link: 'https://search.censys.io/',
|
||||||
icon: 'https://i.ibb.co/j3ZtXzM/censys.png',
|
icon: 'https://i.ibb.co/j3ZtXzM/censys.png',
|
||||||
description: 'Lookup hosts associated with a domain.',
|
description: 'Lookup hosts associated with a domain',
|
||||||
searchLink: 'https://search.censys.io/search?resource=hosts&q={URL}',
|
searchLink: 'https://search.censys.io/search?resource=hosts&q={URL}',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Page Speed Insights',
|
title: 'Page Speed Insights',
|
||||||
link: 'https://developers.google.com/speed/pagespeed/insights/',
|
link: 'https://developers.google.com/speed/pagespeed/insights/',
|
||||||
icon: 'https://i.ibb.co/k68t9bb/Page-speed-insights.png',
|
icon: 'https://i.ibb.co/k68t9bb/Page-speed-insights.png',
|
||||||
description: 'Checks the performance, accessibility and SEO of a page on mobile + desktop.',
|
description: 'Checks the performance, accessibility and SEO of a page on mobile + desktop',
|
||||||
searchLink: 'https://developers.google.com/speed/pagespeed/insights/?url={URL}',
|
searchLink: 'https://developers.google.com/speed/pagespeed/insights/?url={URL}',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -204,6 +204,13 @@ const resources = [
|
|||||||
description: 'View traffic source locations for a domain through Cloudflare',
|
description: 'View traffic source locations for a domain through Cloudflare',
|
||||||
searchLink: 'https://radar.cloudflare.com/domains/domain/{URL}',
|
searchLink: 'https://radar.cloudflare.com/domains/domain/{URL}',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: 'Mozilla Observatory',
|
||||||
|
link: 'https://observatory.mozilla.org/',
|
||||||
|
icon: 'https://i.ibb.co/hBWh9cj/logo-mozm-5e95c457fdd1.png',
|
||||||
|
description: 'Assesses website security posture by analyzing various security headers and practices',
|
||||||
|
searchLink: 'https://observatory.mozilla.org/analyze/{URL}',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const makeLink = (resource: any, scanUrl: string | undefined): string => {
|
const makeLink = (resource: any, scanUrl: string | undefined): string => {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import colors from 'styles/colors';
|
|||||||
interface Props {
|
interface Props {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
title?: string;
|
title?: string;
|
||||||
|
key?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
|
|||||||
@@ -224,6 +224,52 @@ const jobNames = [
|
|||||||
'carbon',
|
'carbon',
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
|
interface JobListItemProps {
|
||||||
|
job: LoadingJob;
|
||||||
|
showJobDocs: (name: string) => void;
|
||||||
|
showErrorModal: (name: string, state: LoadingState, timeTaken: number | undefined, error: string, isInfo?: boolean) => void;
|
||||||
|
barColors: Record<LoadingState, [string, string]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getStatusEmoji = (state: LoadingState): string => {
|
||||||
|
switch (state) {
|
||||||
|
case 'success':
|
||||||
|
return '✅';
|
||||||
|
case 'loading':
|
||||||
|
return '🔄';
|
||||||
|
case 'error':
|
||||||
|
return '❌';
|
||||||
|
case 'timed-out':
|
||||||
|
return '⏸️';
|
||||||
|
case 'skipped':
|
||||||
|
return '⏭️';
|
||||||
|
default:
|
||||||
|
return '❓';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const JobListItem: React.FC<JobListItemProps> = ({ job, showJobDocs, showErrorModal, barColors }) => {
|
||||||
|
const { name, state, timeTaken, retry, error } = job;
|
||||||
|
const actionButton = retry && state !== 'success' && state !== 'loading' ?
|
||||||
|
<FailedJobActionButton onClick={retry}>↻ Retry</FailedJobActionButton> : null;
|
||||||
|
|
||||||
|
const showModalButton = error && ['error', 'timed-out', 'skipped'].includes(state) &&
|
||||||
|
<FailedJobActionButton onClick={() => showErrorModal(name, state, timeTaken, error, state === 'skipped')}>
|
||||||
|
{state === 'timed-out' ? '■ Show Timeout Reason' : '■ Show Error'}
|
||||||
|
</FailedJobActionButton>;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<li key={name}>
|
||||||
|
<b onClick={() => showJobDocs(name)}>{getStatusEmoji(state)} {name}</b>
|
||||||
|
<span style={{color: barColors[state][0]}}> ({state})</span>.
|
||||||
|
<i>{timeTaken && state !== 'loading' ? ` Took ${timeTaken} ms` : ''}</i>
|
||||||
|
{actionButton}
|
||||||
|
{showModalButton}
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
export const initialJobs = jobNames.map((job: string) => {
|
export const initialJobs = jobNames.map((job: string) => {
|
||||||
return {
|
return {
|
||||||
name: job,
|
name: job,
|
||||||
@@ -239,9 +285,9 @@ export const calculateLoadingStatePercentages = (loadingJobs: LoadingJob[]): Rec
|
|||||||
const stateCount: Record<LoadingState, number> = {
|
const stateCount: Record<LoadingState, number> = {
|
||||||
'success': 0,
|
'success': 0,
|
||||||
'loading': 0,
|
'loading': 0,
|
||||||
'skipped': 0,
|
|
||||||
'error': 0,
|
|
||||||
'timed-out': 0,
|
'timed-out': 0,
|
||||||
|
'error': 0,
|
||||||
|
'skipped': 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Count the number of each state
|
// Count the number of each state
|
||||||
@@ -253,9 +299,9 @@ export const calculateLoadingStatePercentages = (loadingJobs: LoadingJob[]): Rec
|
|||||||
const statePercentage: Record<LoadingState, number> = {
|
const statePercentage: Record<LoadingState, number> = {
|
||||||
'success': (stateCount['success'] / totalJobs) * 100,
|
'success': (stateCount['success'] / totalJobs) * 100,
|
||||||
'loading': (stateCount['loading'] / totalJobs) * 100,
|
'loading': (stateCount['loading'] / totalJobs) * 100,
|
||||||
'skipped': (stateCount['skipped'] / totalJobs) * 100,
|
|
||||||
'error': (stateCount['error'] / totalJobs) * 100,
|
|
||||||
'timed-out': (stateCount['timed-out'] / totalJobs) * 100,
|
'timed-out': (stateCount['timed-out'] / totalJobs) * 100,
|
||||||
|
'error': (stateCount['error'] / totalJobs) * 100,
|
||||||
|
'skipped': (stateCount['skipped'] / totalJobs) * 100,
|
||||||
};
|
};
|
||||||
|
|
||||||
return statePercentage;
|
return statePercentage;
|
||||||
@@ -353,26 +399,9 @@ const ProgressLoader = (props: { loadStatus: LoadingJob[], showModal: (err: Reac
|
|||||||
const barColors: Record<LoadingState | string, [string, string]> = {
|
const barColors: Record<LoadingState | string, [string, string]> = {
|
||||||
'success': isDone ? makeBarColor(colors.primary) : makeBarColor(colors.success),
|
'success': isDone ? makeBarColor(colors.primary) : makeBarColor(colors.success),
|
||||||
'loading': makeBarColor(colors.info),
|
'loading': makeBarColor(colors.info),
|
||||||
'skipped': makeBarColor(colors.warning),
|
|
||||||
'error': makeBarColor(colors.danger),
|
'error': makeBarColor(colors.danger),
|
||||||
'timed-out': makeBarColor(colors.neutral),
|
'timed-out': makeBarColor(colors.warning),
|
||||||
};
|
'skipped': makeBarColor(colors.neutral),
|
||||||
|
|
||||||
const getStatusEmoji = (state: LoadingState): string => {
|
|
||||||
switch (state) {
|
|
||||||
case 'success':
|
|
||||||
return '✅';
|
|
||||||
case 'loading':
|
|
||||||
return '🔄';
|
|
||||||
case 'skipped':
|
|
||||||
return '⏭️';
|
|
||||||
case 'error':
|
|
||||||
return '❌';
|
|
||||||
case 'timed-out':
|
|
||||||
return '⏸️';
|
|
||||||
default:
|
|
||||||
return '❓';
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const showErrorModal = (name: string, state: LoadingState, timeTaken: number | undefined, error: string, isInfo?: boolean) => {
|
const showErrorModal = (name: string, state: LoadingState, timeTaken: number | undefined, error: string, isInfo?: boolean) => {
|
||||||
@@ -416,20 +445,9 @@ const ProgressLoader = (props: { loadStatus: LoadingJob[], showModal: (err: Reac
|
|||||||
<Details>
|
<Details>
|
||||||
<summary>Show Details</summary>
|
<summary>Show Details</summary>
|
||||||
<ul>
|
<ul>
|
||||||
{
|
{loadStatus.map((job: LoadingJob) => (
|
||||||
loadStatus.map(({ name, state, timeTaken, retry, error }: LoadingJob) => {
|
<JobListItem key={job.name} job={job} showJobDocs={props.showJobDocs} showErrorModal={showErrorModal} barColors={barColors} />
|
||||||
return (
|
))}
|
||||||
<li key={name}>
|
|
||||||
<b onClick={() => props.showJobDocs(name)}>{getStatusEmoji(state)} {name}</b>
|
|
||||||
<span style={{color : barColors[state][0]}}> ({state})</span>.
|
|
||||||
<i>{(timeTaken && state !== 'loading') ? ` Took ${timeTaken} ms` : '' }</i>
|
|
||||||
{ (retry && state !== 'success' && state !== 'loading') && <FailedJobActionButton onClick={retry}>↻ Retry</FailedJobActionButton> }
|
|
||||||
{ (error && state === 'error') && <FailedJobActionButton onClick={() => showErrorModal(name, state, timeTaken, error)}>■ Show Error</FailedJobActionButton> }
|
|
||||||
{ (error && state === 'skipped') && <FailedJobActionButton onClick={() => showErrorModal(name, state, timeTaken, error, true)}>■ Show Reason</FailedJobActionButton> }
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</ul>
|
</ul>
|
||||||
{ loadStatus.filter((val: LoadingJob) => val.state === 'error').length > 0 &&
|
{ loadStatus.filter((val: LoadingJob) => val.state === 'error').length > 0 &&
|
||||||
<p className="error">
|
<p className="error">
|
||||||
|
|||||||
@@ -35,16 +35,21 @@ const useMotherOfAllHooks = <ResultType = any>(params: UseIpAddressProps<ResultT
|
|||||||
const [result, setResult] = useState<ResultType>();
|
const [result, setResult] = useState<ResultType>();
|
||||||
|
|
||||||
// Fire off the HTTP fetch request, then set results and update loading / error state
|
// Fire off the HTTP fetch request, then set results and update loading / error state
|
||||||
|
|
||||||
const doTheFetch = () => {
|
const doTheFetch = () => {
|
||||||
return fetchRequest()
|
return fetchRequest()
|
||||||
.then((res: any) => {
|
.then((res: any) => {
|
||||||
if (!res) { // No response :(
|
if (!res) { // No response :(
|
||||||
updateLoadingJobs(jobId, 'error', res.error || 'No response', reset);
|
updateLoadingJobs(jobId, 'error', 'No response', reset);
|
||||||
} else if (res.error) { // Response returned an error message
|
} else if (res.error) { // Response returned an error message
|
||||||
updateLoadingJobs(jobId, 'error', res.error, reset);
|
if (res.error.includes("timed-out")) { // Specific handling for timeout errors
|
||||||
|
updateLoadingJobs(jobId, 'timed-out', res.error, reset);
|
||||||
|
} else {
|
||||||
|
updateLoadingJobs(jobId, 'error', res.error, reset);
|
||||||
|
}
|
||||||
} else if (res.skipped) { // Response returned a skipped message
|
} else if (res.skipped) { // Response returned a skipped message
|
||||||
updateLoadingJobs(jobId, 'skipped', res.skipped, reset);
|
updateLoadingJobs(jobId, 'skipped', res.skipped, reset);
|
||||||
} else { // Yay, everything went to plan :)
|
} else { // Yay, everything went to plan :)
|
||||||
setResult(res);
|
setResult(res);
|
||||||
updateLoadingJobs(jobId, 'success', '', undefined, res);
|
updateLoadingJobs(jobId, 'success', '', undefined, res);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,6 +101,18 @@ const Section = styled(StyledCard)`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const SponsorshipContainer = styled.div`
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 1rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
line-height: 1.5rem;
|
||||||
|
img {
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
const makeAnchor = (title: string): string => {
|
const makeAnchor = (title: string): string => {
|
||||||
return title.toLowerCase().replace(/[^\w\s]|_/g, "").replace(/\s+/g, "-");
|
return title.toLowerCase().replace(/[^\w\s]|_/g, "").replace(/\s+/g, "-");
|
||||||
};
|
};
|
||||||
@@ -111,7 +123,7 @@ const About = (): JSX.Element => {
|
|||||||
<AboutContainer>
|
<AboutContainer>
|
||||||
<Nav>
|
<Nav>
|
||||||
<HeaderLinkContainer>
|
<HeaderLinkContainer>
|
||||||
<a href="https://github.com/lissy93/web-check"><Button>View on GitHub</Button></a>
|
<a target="_blank" rel="noreferrer" href="https://github.com/lissy93/web-check"><Button>View on GitHub</Button></a>
|
||||||
</HeaderLinkContainer>
|
</HeaderLinkContainer>
|
||||||
</Nav>
|
</Nav>
|
||||||
|
|
||||||
@@ -121,12 +133,32 @@ const About = (): JSX.Element => {
|
|||||||
<p key={index}>{para}</p>
|
<p key={index}>{para}</p>
|
||||||
))}
|
))}
|
||||||
<hr />
|
<hr />
|
||||||
|
<SponsorshipContainer>
|
||||||
|
<p>
|
||||||
|
Web-Check is kindly sponsored
|
||||||
|
by <a target="_blank" rel="noreferrer" href="https://terminaltrove.com/?utm_campaign=github&utm_medium=referral&utm_content=web-check&utm_source=wcgh">
|
||||||
|
Terminal Trove
|
||||||
|
</a>
|
||||||
|
<br />
|
||||||
|
The $HOME of all things in the terminal.
|
||||||
|
<br />
|
||||||
|
<small>
|
||||||
|
<a target="_blank" rel="noreferrer" href="https://terminaltrove.com/newsletter?utm_campaign=github&utm_medium=referral&utm_content=web-check&utm_source=wcgh">
|
||||||
|
Find your next CLI / TUI tool, and get updates to your inbox
|
||||||
|
</a>
|
||||||
|
</small>
|
||||||
|
</p>
|
||||||
|
<a target="_blank" rel="noreferrer" href="https://terminaltrove.com/?utm_campaign=github&utm_medium=referral&utm_content=web-check&utm_source=wcgh">
|
||||||
|
<img width="300" alt="Terminal Trove" src="https://i.ibb.co/T1KzVmR/terminal-trove-green.png" />
|
||||||
|
</a>
|
||||||
|
</SponsorshipContainer>
|
||||||
|
<hr />
|
||||||
<p>
|
<p>
|
||||||
Web-Check is developed and maintained by <a href="https://aliciasykes.com">Alicia Sykes</a>.
|
Web-Check is developed and maintained by <a target="_blank" rel="noreferrer" href="https://aliciasykes.com">Alicia Sykes</a>.
|
||||||
It's licensed under the <a href="https://github.com/Lissy93/web-check/blob/master/LICENSE">MIT license</a>,
|
It's licensed under the <a target="_blank" rel="noreferrer" href="https://github.com/Lissy93/web-check/blob/master/LICENSE">MIT license</a>,
|
||||||
and is completely free to use, modify and distribute in both personal and commercial settings.<br />
|
and is completely free to use, modify and distribute in both personal and commercial settings.<br />
|
||||||
Source code and self-hosting docs are available on <a href="https://github.com/lissy93/web-check">GitHub</a>.
|
Source code and self-hosting docs are available on <a target="_blank" rel="noreferrer" href="https://github.com/lissy93/web-check">GitHub</a>.
|
||||||
If you've found this service useful, consider <a href="https://github.com/sponsors/Lissy93">sponsoring me</a> from $1/month,
|
If you've found this service useful, consider <a target="_blank" rel="noreferrer" href="https://github.com/sponsors/Lissy93">sponsoring me</a> from $1/month,
|
||||||
to help with the ongoing hosting and development costs.
|
to help with the ongoing hosting and development costs.
|
||||||
</p>
|
</p>
|
||||||
</Section>
|
</Section>
|
||||||
@@ -184,19 +216,19 @@ const About = (): JSX.Element => {
|
|||||||
<p>Web-Check is designed to be easily self-hosted.</p>
|
<p>Web-Check is designed to be easily self-hosted.</p>
|
||||||
<Heading as="h3" size="small" color={colors.primary}>Option #1 - Netlify</Heading>
|
<Heading as="h3" size="small" color={colors.primary}>Option #1 - Netlify</Heading>
|
||||||
<p>Click the button below to deploy to Netlify</p>
|
<p>Click the button below to deploy to Netlify</p>
|
||||||
<a href="https://app.netlify.com/start/deploy?repository=https://github.com/lissy93/web-check">
|
<a target="_blank" rel="noreferrer" href="https://app.netlify.com/start/deploy?repository=https://github.com/lissy93/web-check">
|
||||||
<img src="https://www.netlify.com/img/deploy/button.svg" alt="Deploy to Netlify" />
|
<img src="https://www.netlify.com/img/deploy/button.svg" alt="Deploy to Netlify" />
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<Heading as="h3" size="small" color={colors.primary}>Option #2 - Vercel</Heading>
|
<Heading as="h3" size="small" color={colors.primary}>Option #2 - Vercel</Heading>
|
||||||
<p>Click the button below to deploy to Vercel</p>
|
<p>Click the button below to deploy to Vercel</p>
|
||||||
<a href="https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Flissy93%2Fweb-check&project-name=web-check&repository-name=web-check-fork&demo-title=Web-Check%20Demo&demo-description=Check%20out%20web-check.xyz%20to%20see%20a%20live%20demo%20of%20this%20application%20running.&demo-url=https%3A%2F%2Fweb-check.xyz&demo-image=https%3A%2F%2Fraw.githubusercontent.com%2FLissy93%2Fweb-check%2Fmaster%2F.github%2Fscreenshots%2Fweb-check-screenshot10.png">
|
<a target="_blank" rel="noreferrer" href="https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Flissy93%2Fweb-check&project-name=web-check&repository-name=web-check-fork&demo-title=Web-Check%20Demo&demo-description=Check%20out%20web-check.xyz%20to%20see%20a%20live%20demo%20of%20this%20application%20running.&demo-url=https%3A%2F%2Fweb-check.xyz&demo-image=https%3A%2F%2Fraw.githubusercontent.com%2FLissy93%2Fweb-check%2Fmaster%2F.github%2Fscreenshots%2Fweb-check-screenshot10.png">
|
||||||
<img src="https://vercel.com/button" alt="Deploy with Vercel" />
|
<img src="https://vercel.com/button" alt="Deploy with Vercel" />
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<Heading as="h3" size="small" color={colors.primary}>Option #3 - Docker</Heading>
|
<Heading as="h3" size="small" color={colors.primary}>Option #3 - Docker</Heading>
|
||||||
<p>
|
<p>
|
||||||
A Docker container is published to <a href="https://hub.docker.com/r/lissy93/web-check">DockerHub</a>
|
A Docker container is published to <a target="_blank" rel="noreferrer" href="https://hub.docker.com/r/lissy93/web-check">DockerHub</a>
|
||||||
<br />
|
<br />
|
||||||
Run this command, then open <code>localhost:3000</code>
|
Run this command, then open <code>localhost:3000</code>
|
||||||
<pre>docker run -p 3000:3000 lissy93/web-check</pre>
|
<pre>docker run -p 3000:3000 lissy93/web-check</pre>
|
||||||
@@ -214,7 +246,7 @@ const About = (): JSX.Element => {
|
|||||||
<Heading as="h3" size="small" color={colors.primary}>Further Docs</Heading>
|
<Heading as="h3" size="small" color={colors.primary}>Further Docs</Heading>
|
||||||
<p>
|
<p>
|
||||||
More detailed installation and setup instructions can be found in the
|
More detailed installation and setup instructions can be found in the
|
||||||
GitHub repository - <a href="https://github.com/lissy93/web-check#readme">github.com/lissy93/web-check</a>
|
GitHub repository - <a target="_blank" rel="noreferrer" href="https://github.com/lissy93/web-check#readme">github.com/lissy93/web-check</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<Heading as="h3" size="small" color={colors.primary}>Configuring</Heading>
|
<Heading as="h3" size="small" color={colors.primary}>Configuring</Heading>
|
||||||
@@ -226,17 +258,17 @@ const About = (): JSX.Element => {
|
|||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<code>GOOGLE_CLOUD_API_KEY</code>
|
<code>GOOGLE_CLOUD_API_KEY</code>
|
||||||
: <a href="https://cloud.google.com/api-gateway/docs/authenticate-api-keys">A Google API key</a>
|
: <a target="_blank" rel="noreferrer" href="https://cloud.google.com/api-gateway/docs/authenticate-api-keys">A Google API key</a>
|
||||||
<i> Used to return quality metrics for a site</i>
|
<i> Used to return quality metrics for a site</i>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<code>REACT_APP_SHODAN_API_KEY</code>
|
<code>REACT_APP_SHODAN_API_KEY</code>
|
||||||
: <a href="https://account.shodan.io/">A Shodan API key</a>
|
: <a target="_blank" rel="noreferrer" href="https://account.shodan.io/">A Shodan API key</a>
|
||||||
<i> To show associated hosts for a domain</i>
|
<i> To show associated hosts for a domain</i>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<code>REACT_APP_WHO_API_KEY</code>
|
<code>REACT_APP_WHO_API_KEY</code>
|
||||||
: <a href="https://whoapi.com/">A WhoAPI key</a>
|
: <a target="_blank" rel="noreferrer" href="https://whoapi.com/">A WhoAPI key</a>
|
||||||
<i> Allows for more comprehensive WhoIs records</i>
|
<i> Allows for more comprehensive WhoIs records</i>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -270,11 +302,11 @@ const About = (): JSX.Element => {
|
|||||||
<Section>
|
<Section>
|
||||||
<Heading as="h3" size="small" color={colors.primary}>License</Heading>
|
<Heading as="h3" size="small" color={colors.primary}>License</Heading>
|
||||||
<b>
|
<b>
|
||||||
<a href="https://github.com/lissy93/web-check">Web-Check</a> is distributed under the MIT license,
|
<a target="_blank" rel="noreferrer" href="https://github.com/lissy93/web-check">Web-Check</a> is distributed under the MIT license,
|
||||||
© <a href="https://aliciasykes.com">Alicia Sykes</a> { new Date().getFullYear()}
|
© <a target="_blank" rel="noreferrer" href="https://aliciasykes.com">Alicia Sykes</a> { new Date().getFullYear()}
|
||||||
</b>
|
</b>
|
||||||
<br />
|
<br />
|
||||||
<small>For more info, see <a href="https://tldrlegal.com/license/mit-license">TLDR Legal → MIT</a></small>
|
<small>For more info, see <a target="_blank" rel="noreferrer" href="https://tldrlegal.com/license/mit-license">TLDR Legal → MIT</a></small>
|
||||||
<pre>{license}</pre>
|
<pre>{license}</pre>
|
||||||
<hr />
|
<hr />
|
||||||
<Heading as="h3" size="small" color={colors.primary}>Fair Use</Heading>
|
<Heading as="h3" size="small" color={colors.primary}>Fair Use</Heading>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ const HomeContainer = styled.section`
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
font-family: 'PTMono';
|
font-family: 'PTMono';
|
||||||
padding: 0 1rem;
|
padding: 1.5rem 1rem 4rem 1rem;
|
||||||
footer {
|
footer {
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
@@ -34,10 +34,52 @@ const UserInputMain = styled.form`
|
|||||||
z-index: 5;
|
z-index: 5;
|
||||||
margin: 1rem;
|
margin: 1rem;
|
||||||
width: calc(100% - 2rem);
|
width: calc(100% - 2rem);
|
||||||
max-width: 50rem;
|
max-width: 60rem;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const SponsorCard = styled.div`
|
||||||
|
background: ${colors.backgroundLighter};
|
||||||
|
box-shadow: 4px 4px 0px ${colors.bgShadowColor};
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 1rem;
|
||||||
|
z-index: 5;
|
||||||
|
margin: 1rem;
|
||||||
|
width: calc(100% - 2rem);
|
||||||
|
max-width: 60rem;
|
||||||
|
z-index: 2;
|
||||||
|
.inner {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 1rem;
|
||||||
|
p {
|
||||||
|
margin: 0.25rem 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: ${colors.textColor};
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
box-shadow: 2px 2px 0px ${colors.fgShadowColor};
|
||||||
|
transition: box-shadow 0.2s;
|
||||||
|
margin: 0 auto;
|
||||||
|
display: block;
|
||||||
|
width: 200px;
|
||||||
|
&:hover {
|
||||||
|
box-shadow: 4px 4px 0px ${colors.fgShadowColor};
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
box-shadow: -2px -2px 0px ${colors.fgShadowColor};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.cta {
|
||||||
|
font-size: 0.78rem;
|
||||||
|
a { color: ${colors.primary}; }
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
// const FindIpButton = styled.a`
|
// const FindIpButton = styled.a`
|
||||||
// margin: 0.5rem;
|
// margin: 0.5rem;
|
||||||
// cursor: pointer;
|
// cursor: pointer;
|
||||||
@@ -55,7 +97,7 @@ const ErrorMessage = styled.p`
|
|||||||
const SiteFeaturesWrapper = styled(StyledCard)`
|
const SiteFeaturesWrapper = styled(StyledCard)`
|
||||||
margin: 1rem;
|
margin: 1rem;
|
||||||
width: calc(100% - 2rem);
|
width: calc(100% - 2rem);
|
||||||
max-width: 50rem;
|
max-width: 60rem;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
.links {
|
.links {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -173,6 +215,28 @@ const Home = (): JSX.Element => {
|
|||||||
{ errorMsg && <ErrorMessage>{errorMsg}</ErrorMessage>}
|
{ errorMsg && <ErrorMessage>{errorMsg}</ErrorMessage>}
|
||||||
<Button styles="width: calc(100% - 1rem);" size="large" onClick={submit}>Analyze!</Button>
|
<Button styles="width: calc(100% - 1rem);" size="large" onClick={submit}>Analyze!</Button>
|
||||||
</UserInputMain>
|
</UserInputMain>
|
||||||
|
<SponsorCard>
|
||||||
|
<Heading as="h2" size="small" color={colors.primary}>Sponsored by</Heading>
|
||||||
|
<div className="inner">
|
||||||
|
<p>
|
||||||
|
<a target="_blank" rel="noreferrer" href="https://terminaltrove.com/?utm_campaign=github&utm_medium=referral&utm_content=web-check&utm_source=wcgh">
|
||||||
|
Terminal Trove
|
||||||
|
</a> - The $HOME of all things in the terminal.
|
||||||
|
<br />
|
||||||
|
<span className="cta">
|
||||||
|
Get updates on the latest CLI/TUI tools via
|
||||||
|
the <a target="_blank" rel="noreferrer" className="cta" href="https://terminaltrove.com/newsletter?utm_campaign=github&utm_medium=referral&utm_content=web-check&utm_source=wcgh">
|
||||||
|
Terminal Trove newsletter
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<a target="_blank" rel="noreferrer" href="https://terminaltrove.com/?utm_campaign=github&utm_medium=referral&utm_content=web-check&utm_source=wcgh">
|
||||||
|
<img width="120" alt="Terminal Trove" src="https://i.ibb.co/NKtYjJ1/terminal-trove-web-check.png" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</SponsorCard>
|
||||||
<SiteFeaturesWrapper>
|
<SiteFeaturesWrapper>
|
||||||
<div className="features">
|
<div className="features">
|
||||||
<Heading as="h2" size="small" color={colors.primary}>Supported Checks</Heading>
|
<Heading as="h2" size="small" color={colors.primary}>Supported Checks</Heading>
|
||||||
@@ -182,10 +246,10 @@ const Home = (): JSX.Element => {
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div className="links">
|
<div className="links">
|
||||||
<a href="https://github.com/lissy93/web-check" title="Check out the source code and documentation on GitHub, and get support or contribute">
|
<a target="_blank" rel="noreferrer" href="https://github.com/lissy93/web-check" title="Check out the source code and documentation on GitHub, and get support or contribute">
|
||||||
<Button>View on GitHub</Button>
|
<Button>View on GitHub</Button>
|
||||||
</a>
|
</a>
|
||||||
<a href="https://app.netlify.com/start/deploy?repository=https://github.com/lissy93/web-check" title="Deploy your own private or public instance of Web-Check to Netlify">
|
<a target="_blank" rel="noreferrer" href="https://app.netlify.com/start/deploy?repository=https://github.com/lissy93/web-check" title="Deploy your own private or public instance of Web-Check to Netlify">
|
||||||
<Button>Deploy your own</Button>
|
<Button>Deploy your own</Button>
|
||||||
</a>
|
</a>
|
||||||
<a href="/about#api-documentation" title="View the API documentation, to use Web-Check programmatically">
|
<a href="/about#api-documentation" title="View the API documentation, to use Web-Check programmatically">
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ const NotFound = (): JSX.Element => {
|
|||||||
<HeaderLinkContainer>
|
<HeaderLinkContainer>
|
||||||
<a href="/"><Button>Back to Homepage</Button></a>
|
<a href="/"><Button>Back to Homepage</Button></a>
|
||||||
</HeaderLinkContainer>
|
</HeaderLinkContainer>
|
||||||
<a href="https://github.com/lissy93/web-check">Report Issue</a>
|
<a target="_blank" rel="noreferrer" href="https://github.com/lissy93/web-check">Report Issue</a>
|
||||||
</NotFoundInner>
|
</NotFoundInner>
|
||||||
</AboutContainer>
|
</AboutContainer>
|
||||||
<Footer isFixed={true} />
|
<Footer isFixed={true} />
|
||||||
|
|||||||
@@ -208,12 +208,24 @@ const Results = (): JSX.Element => {
|
|||||||
console.log(
|
console.log(
|
||||||
`%cFetch Error - ${job}%c\n\n${timeString}%c The ${job} job failed `
|
`%cFetch Error - ${job}%c\n\n${timeString}%c The ${job} job failed `
|
||||||
+`after ${timeTaken}ms, with the following error:%c\n${error}`,
|
+`after ${timeTaken}ms, with the following error:%c\n${error}`,
|
||||||
`background: ${colors.danger}; padding: 4px 8px; font-size: 16px;`,
|
`background: ${colors.danger}; color:${colors.background}; padding: 4px 8px; font-size: 16px;`,
|
||||||
`font-weight: bold; color: ${colors.danger};`,
|
`font-weight: bold; color: ${colors.danger};`,
|
||||||
`color: ${colors.danger};`,
|
`color: ${colors.danger};`,
|
||||||
`color: ${colors.warning};`,
|
`color: ${colors.warning};`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (newState === 'timed-out') {
|
||||||
|
console.log(
|
||||||
|
`%cFetch Timeout - ${job}%c\n\n${timeString}%c The ${job} job timed out `
|
||||||
|
+`after ${timeTaken}ms, with the following error:%c\n${error}`,
|
||||||
|
`background: ${colors.info}; color:${colors.background}; padding: 4px 8px; font-size: 16px;`,
|
||||||
|
`font-weight: bold; color: ${colors.info};`,
|
||||||
|
`color: ${colors.info};`,
|
||||||
|
`color: ${colors.warning};`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return newJobs;
|
return newJobs;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -225,8 +237,9 @@ const Results = (): JSX.Element => {
|
|||||||
.then(data => resolve(data))
|
.then(data => resolve(data))
|
||||||
.catch(error => resolve(
|
.catch(error => resolve(
|
||||||
{ error: `Failed to get a valid response 😢\n`
|
{ error: `Failed to get a valid response 😢\n`
|
||||||
+ `This is likely due the target not exposing the required data, `
|
+ 'This is likely due the target not exposing the required data, '
|
||||||
+ `or limitations in how Netlify executes lambda functions, such as the 10-sec timeout.\n\n`
|
+ 'or limitations in imposed by the infrastructure this instance '
|
||||||
|
+ 'of Web Check is running on.\n\n'
|
||||||
+ `Error info:\n${error}`}
|
+ `Error info:\n${error}`}
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
@@ -288,7 +301,7 @@ const Results = (): JSX.Element => {
|
|||||||
addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
|
addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
|
||||||
fetchRequest: () => fetch(`${api}/quality?url=${address}`)
|
fetchRequest: () => fetch(`${api}/quality?url=${address}`)
|
||||||
.then(res => parseJson(res))
|
.then(res => parseJson(res))
|
||||||
.then(res => res?.lighthouseResult || { error: 'No Data'}),
|
.then(res => res?.lighthouseResult || { error: res.error || 'No Data' }),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get the technologies used to build site, using Wappalyzer
|
// Get the technologies used to build site, using Wappalyzer
|
||||||
@@ -857,7 +870,7 @@ const Results = (): JSX.Element => {
|
|||||||
<Nav>
|
<Nav>
|
||||||
{ address &&
|
{ address &&
|
||||||
<Heading color={colors.textColor} size="medium">
|
<Heading color={colors.textColor} size="medium">
|
||||||
{ addressType === 'url' && <a href={address}><img width="32px" src={`https://icon.horse/icon/${makeSiteName(address)}`} alt="" /></a> }
|
{ addressType === 'url' && <a target="_blank" rel="noreferrer" href={address}><img width="32px" src={`https://icon.horse/icon/${makeSiteName(address)}`} alt="" /></a> }
|
||||||
{makeSiteName(address)}
|
{makeSiteName(address)}
|
||||||
</Heading>
|
</Heading>
|
||||||
}
|
}
|
||||||
@@ -894,7 +907,7 @@ const Results = (): JSX.Element => {
|
|||||||
<a href="#view-download-raw-data"><span className="toggle-filters">Export Data</span></a>
|
<a href="#view-download-raw-data"><span className="toggle-filters">Export Data</span></a>
|
||||||
<a href="/about"><span className="toggle-filters">Learn about the Results</span></a>
|
<a href="/about"><span className="toggle-filters">Learn about the Results</span></a>
|
||||||
<a href="/about#additional-resources"><span className="toggle-filters">More tools</span></a>
|
<a href="/about#additional-resources"><span className="toggle-filters">More tools</span></a>
|
||||||
<a href="https://github.com/lissy93/web-check"><span className="toggle-filters">View GitHub</span></a>
|
<a target="_blank" rel="noreferrer" href="https://github.com/lissy93/web-check"><span className="toggle-filters">View GitHub</span></a>
|
||||||
</div>
|
</div>
|
||||||
) }
|
) }
|
||||||
</FilterButtons>
|
</FilterButtons>
|
||||||
@@ -910,7 +923,7 @@ const Results = (): JSX.Element => {
|
|||||||
&& title.toLowerCase().includes(searchTerm.toLowerCase())
|
&& title.toLowerCase().includes(searchTerm.toLowerCase())
|
||||||
&& (result && !result.error);
|
&& (result && !result.error);
|
||||||
return show ? (
|
return show ? (
|
||||||
<ErrorBoundary title={title}>
|
<ErrorBoundary title={title} key={`eb-${index}`}>
|
||||||
<Component
|
<Component
|
||||||
key={`${title}-${index}`}
|
key={`${title}-${index}`}
|
||||||
data={{...result}}
|
data={{...result}}
|
||||||
|
|||||||
@@ -529,7 +529,7 @@ and the web of connections within a site's architecture.
|
|||||||
The results can also help optimizing server responses, configuring redirects,
|
The results can also help optimizing server responses, configuring redirects,
|
||||||
managing cookies, or fine-tuning DNS records for your site.`,
|
managing cookies, or fine-tuning DNS records for your site.`,
|
||||||
|
|
||||||
`So, weather you're a developer, system administrator, security researcher, penetration
|
`So, whether you're a developer, system administrator, security researcher, penetration
|
||||||
tester or are just interested in discovering the underlying technologies of a given site
|
tester or are just interested in discovering the underlying technologies of a given site
|
||||||
- I'm sure you'll find this a useful addition to your toolbox.`,
|
- I'm sure you'll find this a useful addition to your toolbox.`,
|
||||||
];
|
];
|
||||||
@@ -557,7 +557,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||||||
|
|
||||||
export const supportUs = [
|
export const supportUs = [
|
||||||
"Web-Check is free to use without restriction.",
|
"Web-Check is free to use without restriction.",
|
||||||
"All the code is open source, so you're also free to deploy your own instance, as well as fork, modify and distribute the code in both private and commerical settings.",
|
"All the code is open source, so you're also free to deploy your own instance, as well as fork, modify and distribute the code in both private and commercial settings.",
|
||||||
"Running web-check does cost me a small amount of money each month, so if you're finding the app useful, consider <a href='https://github.com/sponsors/Lissy93'>sponsoring me on GitHub</a> if you're able to. Even just $1 or $2/month would be a huge help in supporting the ongoing project running costs.",
|
"Running web-check does cost me a small amount of money each month, so if you're finding the app useful, consider <a href='https://github.com/sponsors/Lissy93'>sponsoring me on GitHub</a> if you're able to. Even just $1 or $2/month would be a huge help in supporting the ongoing project running costs.",
|
||||||
"Otherwise, there are other ways you can help out, like submitting or reviewing a pull request to the <a href='https://github.com/Lissy93/web-check'>GitHub repo</a>, upvoting us on <a href='https://www.producthunt.com/posts/web-check'>Product Hunt</a>, or by sharing with your network.",
|
"Otherwise, there are other ways you can help out, like submitting or reviewing a pull request to the <a href='https://github.com/Lissy93/web-check'>GitHub repo</a>, upvoting us on <a href='https://www.producthunt.com/posts/web-check'>Product Hunt</a>, or by sharing with your network.",
|
||||||
"But don't feel obliged to do anything, as this app (and all my other projects) will always remain 100% free and open source, and I will do my best to ensure the managed instances remain up and available for as long as possible :)",
|
"But don't feel obliged to do anything, as this app (and all my other projects) will always remain 100% free and open source, and I will do my best to ensure the managed instances remain up and available for as long as possible :)",
|
||||||
|
|||||||
7
vercel.json
Normal file
7
vercel.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"functions": {
|
||||||
|
"api/*.js": {
|
||||||
|
"maxDuration": 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
yarn.lock
11
yarn.lock
@@ -7236,9 +7236,9 @@ caniuse-api@^3.0.0:
|
|||||||
lodash.uniq "^4.5.0"
|
lodash.uniq "^4.5.0"
|
||||||
|
|
||||||
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001464, caniuse-lite@^1.0.30001503:
|
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001464, caniuse-lite@^1.0.30001503:
|
||||||
version "1.0.30001517"
|
version "1.0.30001591"
|
||||||
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001517.tgz"
|
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001591.tgz"
|
||||||
integrity sha512-Vdhm5S11DaFVLlyiKu4hiUTkpZu+y1KA/rZZqVQfOD5YdDT/eQKlkt7NaE0WGOFgX32diqt9MiP9CAiFeRklaA==
|
integrity sha512-PCzRMei/vXjJyL5mJtzNiUCKP59dm8Apqc3PH8gJkMnMXZGox93RbE76jHsmLwmIo6/3nsYIpJtx0O7u5PqFuQ==
|
||||||
|
|
||||||
case-sensitive-paths-webpack-plugin@^2.4.0:
|
case-sensitive-paths-webpack-plugin@^2.4.0:
|
||||||
version "2.4.0"
|
version "2.4.0"
|
||||||
@@ -9788,6 +9788,11 @@ express-logging@1.1.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
on-headers "^1.0.0"
|
on-headers "^1.0.0"
|
||||||
|
|
||||||
|
express-rate-limit@^7.2.0:
|
||||||
|
version "7.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-7.2.0.tgz#06ce387dd5388f429cab8263c514fc07bf90a445"
|
||||||
|
integrity sha512-T7nul1t4TNyfZMJ7pKRKkdeVJWa2CqB8NA1P8BwYaoDI5QSBZARv5oMS43J7b7I5P+4asjVXjb7ONuwDKucahg==
|
||||||
|
|
||||||
express@4.18.2, express@^4.17.3:
|
express@4.18.2, express@^4.17.3:
|
||||||
version "4.18.2"
|
version "4.18.2"
|
||||||
resolved "https://registry.npmjs.org/express/-/express-4.18.2.tgz"
|
resolved "https://registry.npmjs.org/express/-/express-4.18.2.tgz"
|
||||||
|
|||||||
Reference in New Issue
Block a user