Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/saloniamatteo/openalias
Improved OpenAlias API WebForm, with a sleek, modern look
https://github.com/saloniamatteo/openalias
bitcoin btc composer laravel monero oa oa1 open-alias openalias openalias-api openalias-api-webform openalias-webui php xmr
Last synced: about 21 hours ago
JSON representation
Improved OpenAlias API WebForm, with a sleek, modern look
- Host: GitHub
- URL: https://github.com/saloniamatteo/openalias
- Owner: saloniamatteo
- License: agpl-3.0
- Created: 2022-09-11T11:25:01.000Z (over 2 years ago)
- Default Branch: master
- Last Pushed: 2025-01-02T19:30:17.000Z (9 days ago)
- Last Synced: 2025-01-02T20:29:12.792Z (9 days ago)
- Topics: bitcoin, btc, composer, laravel, monero, oa, oa1, open-alias, openalias, openalias-api, openalias-api-webform, openalias-webui, php, xmr
- Language: PHP
- Homepage: https://oa.salonia.it
- Size: 1.96 MB
- Stars: 3
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
README
# [OpenAlias WebUI](https://oa.salonia.it)
OpenAlias web portal to easily retrieve OpenAlias records of any domain.This website is built in **PHP** with the following:
- **Backend**: [Laravel](https://laravel.com)
- **Bundler**: [Vite](https://vite.dev) + [PurgeCSS](https://purgecss.com)The following are used for the front-end:
- **Framework**: [CirrusUI](https://cirrus-ui.com)
- **Icons**: [Lucide](https://lucide.dev)## Donate
Support this project: [salonia.it/donate](https://salonia.it/donate)## Screenshots
Landing page:
![oa](Pictures/oa.png)Page with results:
![oa-records](Pictures/oa-records.png)Page with no results:
![oa-norecords](Pictures/oa-norecords.png)## Features
### DNSSEC validation
Each requested domain is checked for presence of `RRSIG` records,
which confirm DNSSEC validity.The validation is done with the following command: `host -t RRSIG `,
where `` corresponds to the requested domain, already sanitized.The results are then displayed on top of the records table,
showing a white check mark on a green background (✅),
or a white cross on a red background (❎),
followed, respectively, by **DNSSEC OK**, or **DNSSEC FAIL**.### AbuseIPDB
This Middleware, written by me, checks if the incoming IP address comes from
a "bad" server (crawlers, scanners, etc.), thanks to
[AbuseIPDB](https://www.abuseipdb.com/faq.html)'s `/check` API endpoint.When a request is received, the `BlockRequest` Middleware will check the cache,
using the incoming IP as key. If a record is found, check if it is a good IP:
if it is, proceed with the request. If it isn't, throw a `403`, which will be
rendered with a pretty page, regardless.If no records are found in the cache, `BlockRequest` queries AbuseIPDB,
honoring the user-provided options (see below). If the IP address is
whitelisted, check if the user wants to ignore this whitelist;
we then check the IP score and, if it is above a certain threshold,
the request will be blocked, like the case above, throwing a `403`.To use this, create an account, then head over to [AbuseIPDB/api](https://www.abuseipdb.com/account/api)
and create an APIv2 key. Save this key into the `.env` file:```env
# If you want to block incoming requests from bad servers
# using AbuseIPDB, enter your API key here.
ABUSEIPDB_KEY= # Your API key goes here!
```You're all set! Make sure the cache store is also properly configured.
The cache store provided with this site is `file`, so you should be good.Additionally, you can tune the following parameters:
- `ABUSEIPDB_THRESHOLD`: The minimum percentage score required
for an IP to be considered malicious. Default: `35`.
- `ABUSEIPDB_IGNORE_WHITELIST`: Ignore AbuseIPDB's whitelist preference
for every IP. Default: `0`.
- `ABUSEIPDB_CACHE_TTL`: Store the results in cache for x minutes. Default: `15`
- `ABUSEIPDB_IP_OK`: Store this string for a known good IP. Default: `OK`
- `ABUSEIPDB_IP_BAD`: Store this string for a known bad IP. Default: `BAD`### Rate limiter
Apart from the AbuseIPDB integration, this website uses Laravel's
[rate limiter](https://laravel.com/docs/11.x/rate-limiting).
It uses the same `CACHE_STORE` driver as the AbuseIPDB integration,
which defaults to `file`.The rate limiter is defined in `app/Providers/AppServiceProvider.php` as follows:
```php
/* Bootstrap any application services. */
public function boot()
{
// Limit to 5 requests per minute.
RateLimiter::for('global', function (Request $request) {
if (config('APP_ENV') == 'production') {
return Limit::perMinute(5)->by($request->ip());
}
});
}
```It is configured to allow a maximum of **5 page requests per minute**,
before throwing an HTTP 429 (Too many requests).### Asset bundling
Assets are bundled and handled by Vite:
- CSS & JS files are minified (PostCSS and PurgeCSS) and versioned
- Images are versionedThis helps with removing unused code, lowering asset size, and lowering page load times.
Run `npm run build` to re-generate the asset bundle.
### Components
Most HTML components (Card, Hero, Tile, etc.) are split up in several files, under `resources/views/components/`.
This makes it way easier and faster to write new pages, thanks to Blade Templates.### Caching
Config, events, views, and routes are cached, making site load-times faster.Run `composer cache` to cache them.
### Minification
Every page is minified. Laravel does not do this by default, and there does not
seem to be a "standard" way to do it, other than downloading some shady package.I've implemented my own simple HTML minifier, making use of PHP's output buffering.
Additionally, CSS & JS files are minified by PurgeCSS and Vite, respectively.
## Dependencies
To deploy this website, you need the following:
- `php`
- `composer`
- `nodejs` with `npm`## Setup
- Clone the repo: `git clone https://github.com/saloniamatteo/openalias`
- Change directory: `cd openalias`
- Install PHP dependencies: `composer install`
- Install node dependencies: `npm i`
- Generate `APP_KEY`: `php artisan key:generate`Note that you also may need to change file permissions and/or owner
depending on your setup. If you do, run the following command:```bash
git config core.fileMode false
```This stops git from tracking file permission changes.
If you want to deploy the website locally, copy `.env.example` to `.env`:
```bash
cp .env.example .env
```Make sure you modify `.env`, and uncomment the following:
```env
# Uncomment these values if running locally
APP_ENV=local
APP_DEBUG=true
APP_URL="http://localhost"
```The website can now be deployed using the built-in webserver, `php artisan serve`:
it will be reachable at `localhost` on port `8000`.If you want to use the built-in webserver, make sure you set `APP_URL` to your website's URL.
If you want to serve this website to the Internet, please make sure you don't use
`php spark serve`, and rather have a real server.
I use [nginx](https://nginx.org) with [FastCGI](https://nginx.org/en/docs/http/ngx_http_fastcgi_module.html).Make sure you also disable access to `/build/assets/manifest.json`!
When updating, you may use the `update.sh` script under the `scripts/` folder:
```bash
./scripts/update.sh
```This does the following:
- Installs the composer + npm dependencies
- Generates a new key, forcefully
- Bundles the assets
- Caches config, events, routes, views.### Assets
Make sure you bundle the assets used in the website (CSS, fonts, images):```sh
npm run build
```### Cache
When running in production, it is recommended to cache PHP assets with the following command:```sh
composer cache
```This will cache PHP config, events, routes, views.
### Sample nginx config
Note: this config makes the following assumptions:
- Your site is hosted at `oa.example.com`
- You use LetsEncrypt (`certbot`) and have deployed an SSL certificate
- Your `nginx` build supports HTTP2 and HTTP3 (QUIC)
- You have IPv6 support enabled
- You use port 80 for HTTP and port 443 for HTTPS
- You use php-fpm (FastCGI) and call it via `/var/run/php-fpm.sock`
- You want to disable client uploads
- You want to redirect every HTTP request to the HTTPS port
- You want to allow `robots.txt`
- You want to disable `.well-known`Make sure you movify everything that says "Change this"!
```nginx
# Optional: Rate-limits
#limit_req_zone $binary_remote_addr zone=oa_css:10m rate=10r/s;
#limit_req_zone $binary_remote_addr zone=oa_img:10m rate=5r/s;# Optional: Bandwidth limits
#limit_conn_zone $binary_remote_addr zone=oa_conn_css:10m;
#limit_conn_zone $binary_remote_addr zone=oa_conn_img:10m;server {
# HTTP/1.1 & HTTP/2
listen 443 ssl;
listen [::]:443 ssl;# HTTP/3 (QUIC)
listen 443 quic;
listen [::]:443 quic;# Change this!
server_name oa.example.com;# If the host isn't oa.example.com, redirect the client
if ($host != oa.example.com) {
return 301 https://oa.example.com$request_uri;
}# HTTP2/3
http2 on;
http3 on;
quic_gso on;
quic_retry on;
ssl_early_data on;# SSL
ssl_stapling on;
ssl_stapling_verify on;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_certificate /etc/letsencrypt/live/oa.example.com/fullchain.pem; # Change this!
ssl_certificate_key /etc/letsencrypt/live/oa.example.com/privkey.pem; # Change this!
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;# Site root
# Change this!
root /var/www/oa/public;# Prevent nginx HTTP Server Detection
server_tokens off;# Only allow GET requests
if ($request_method !~* ^GET$) {
return 405;
}# Disable uploads
client_max_body_size 0;
client_body_timeout 0s;
fastcgi_buffers 64 4K;# The settings allows you to optimize the HTTP2 bandwidth.
# See https://blog.cloudflare.com/delivering-http-2-upload-speed-improvements for tuning hints
client_body_buffer_size 512k;# Specify how to handle directories -- specifying `/index.php$request_uri`
# here as the fallback means that Nginx always exhibits the desired behaviour
# when a client requests a path that corresponds to a directory that exists
# on the server. In particular, if that directory contains an index.php file,
# that file is correctly served; if it doesn't, then the request is passed to
# the front-end controller. This consistent behaviour means that we don't need
# to specify custom rules for certain paths (e.g. images and other assets,
# `/updater`, `/ocm-provider`, `/ocs-provider`), and thus
# `try_files $uri $uri/ /index.php$request_uri`
# always provides the desired behaviour.
index index.php index.html /index.php$request_uri;# Allow robots.txt
location = /robots.txt {
allow all;
log_not_found off;
}# Allow .well-known/security.txt
location = /.well-known/security.txt {
allow all;
log_not_found off;
}# Prepend all requests with "/index.php" -- this acts as our front controller.
# index.php handles all requests, but we have to hide it.
# The line below allows us to do exactly what we want.
location / {
rewrite ^ /index.php;
}# Ensure this block, which passes PHP files to the PHP process, is above the blocks
# which handle static assets (as seen below). If this block is not declared first,
# then Nginx will encounter an infinite rewriting loop when it prepends `/index.php`
# to the URI, resulting in a HTTP 500 error response.
location ~ \.php(?:$|/) {
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
set $path_info $fastcgi_path_info;# Try to load requested file. If it doesn't exist, instead
# of throwing a 404, load the front controller, where
# we can load a pretty 404 page.
try_files $fastcgi_script_name /index.php/$fastcgi_script_name;include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param PATH_INFO $path_info;
fastcgi_param HTTPS on;fastcgi_param modHeadersAvailable true; # Avoid sending the security headers twice
fastcgi_param front_controller_active true; # Enable pretty urls
fastcgi_pass unix:/var/run/php-fpm.sock;fastcgi_intercept_errors on;
fastcgi_request_buffering off;
fastcgi_max_temp_file_size 0;# Remove X-Powered-By, which is an information leak
fastcgi_hide_header X-Powered-By;# Do not show ratelimit
fastcgi_hide_header X-Ratelimit-Limit;
fastcgi_hide_header X-Ratelimit-Remaining;# Enable gzip but do not remove ETag headers
gzip on;
gzip_vary on;
gzip_comp_level 4;
gzip_min_length 256;
gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
gzip_types text/plain;# Inform clients that HTTP3 is available
add_header Alt-Svc 'h3=":443"; ma=86400';# COOP/COEP. Disable if you use external plugins/images/assets
add_header Cross-Origin-Opener-Policy "same-origin" always;
add_header Cross-Origin-Embedder-Policy "require-corp" always;
add_header Cross-Origin-Resource-Policy "same-origin" always;# Content Security Policy
# See: https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
# This policy allows only internal assets.
add_header Content-Security-Policy "default-src 'self'; img-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; child-src 'self';";# HSTS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;# HTTP response headers borrowed from Nextcloud `.htaccess`
add_header Referrer-Policy "no-referrer";
add_header X-Content-Type-Options "nosniff";
add_header X-Download-Options "noopen";
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Permitted-Cross-Domain-Policies "none";
add_header X-XSS-Protection "0";# Tell browsers to use per-origin process isolation
add_header Origin-Agent-Cluster "?1" always;
}# CSS & JS
location ~ \.(?:css|js|woff2)$ {
# Limit access to CSS & JS
# Set a burst of 15, and start delaying after the 10th req.
#limit_req zone=oa_css burst=15 delay=10;
#limit_req_log_level warn;
#limit_req_status 429;# Cap bandwidth to 1MB/s after 1MB,
# allowing 5 concurrent requests
#limit_conn oa_conn_css 5;
#limit_rate_after 1M;
#limit_rate 1M;# Enable gzip but do not remove ETag headers
gzip on;
gzip_vary on;
gzip_comp_level 4;
gzip_min_length 256;
gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
gzip_types font/woff2 text/css text/javascript text/plain;add_header Alt-Svc 'h3=":443"; ma=86400';
add_header X-Content-Type-Options "nosniff";
add_header X-Frame-Options "SAMEORIGIN";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;try_files $uri /index.php$request_uri;
expires 10d;
access_log off;
}# Images
location ~ \.(?:gif|ico|jpg|jpeg|pdf|png|svg|webp)$ {
# Limit access to images
# Set a burst of 10, and start delaying after the 5th req.
#limit_req zone=oa_img burst=10 delay=5;
#limit_req_log_level warn;
#limit_req_status 429;# Cap bandwidth to 1MB/s after 1MB,
# allowing 5 concurrent requests
#limit_conn oa_conn_img 5;
#limit_rate_after 1M;
#limit_rate 1M;add_header Alt-Svc 'h3=":443"; ma=86400';
add_header X-Content-Type-Options "nosniff";
add_header X-Frame-Options "SAMEORIGIN";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;try_files $uri /index.php$request_uri;
expires 14d;
access_log off;
}
}server {
listen 80;
listen [::]:80;# Change this!
server_name oa.example.com;# Prevent nginx HTTP Server Detection
server_tokens off;# Change this!
return 301 https://oa.example.com$request_uri;
}
```