{"id":24113804,"url":"https://github.com/saloniamatteo/openalias","last_synced_at":"2026-03-17T16:06:51.985Z","repository":{"id":95243344,"uuid":"535275958","full_name":"saloniamatteo/openalias","owner":"saloniamatteo","description":"Improved OpenAlias API WebForm, with a sleek, modern look","archived":false,"fork":false,"pushed_at":"2025-01-02T19:30:17.000Z","size":2050,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-01-02T20:29:12.792Z","etag":null,"topics":["bitcoin","btc","composer","laravel","monero","oa","oa1","open-alias","openalias","openalias-api","openalias-api-webform","openalias-webui","php","xmr"],"latest_commit_sha":null,"homepage":"https://oa.salonia.it","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/saloniamatteo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"saloniamatteo","custom":["https://salonia.it/donate","https://paypal.me/saloniamatteo"]}},"created_at":"2022-09-11T11:25:01.000Z","updated_at":"2025-01-02T19:30:20.000Z","dependencies_parsed_at":"2025-01-02T20:23:10.897Z","dependency_job_id":"77b6ceb1-ef91-423e-9bad-162184e4351e","html_url":"https://github.com/saloniamatteo/openalias","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saloniamatteo%2Fopenalias","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saloniamatteo%2Fopenalias/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saloniamatteo%2Fopenalias/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saloniamatteo%2Fopenalias/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/saloniamatteo","download_url":"https://codeload.github.com/saloniamatteo/openalias/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":233441613,"owners_count":18676724,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bitcoin","btc","composer","laravel","monero","oa","oa1","open-alias","openalias","openalias-api","openalias-api-webform","openalias-webui","php","xmr"],"created_at":"2025-01-11T04:40:16.381Z","updated_at":"2025-09-18T02:33:11.729Z","avatar_url":"https://github.com/saloniamatteo.png","language":"PHP","funding_links":["https://github.com/sponsors/saloniamatteo","https://salonia.it/donate","https://paypal.me/saloniamatteo"],"categories":[],"sub_categories":[],"readme":"# [OpenAlias WebUI](https://oa.salonia.it)\nOpenAlias web portal to easily retrieve OpenAlias records of any domain.\n\nThis website is built in **PHP** with the following:\n- **Backend**: [Laravel](https://laravel.com)\n- **Bundler**: [Vite](https://vite.dev) + [PurgeCSS](https://purgecss.com)\n\nThe following are used for the front-end:\n- **Framework**: [CirrusUI](https://cirrus-ui.com)\n- **Icons**: [Lucide](https://lucide.dev)\n\nAdditionally, the following are used for debugging of perf data:\n- [Buggregator Trap](https://docs.buggregator.dev/trap/what-is-trap.html)\n- [XHProf](https://github.com/longxinH/xhprof)\n- [XHProf-Buggregator-Laravel](https://github.com/maantje/xhprof-buggregator-laravel)\n\n## Donate\nSupport this project: [salonia.it/donate](https://salonia.it/donate)\n\n## Screenshots\nLanding page:\n![oa](Pictures/oa.png)\n\nPage with results:\n![oa-records](Pictures/oa-records.png)\n\nPage with no results:\n![oa-norecords](Pictures/oa-norecords.png)\n\n## Features\n### DNSSEC validation\nEach requested domain is checked for presence of `RRSIG` records,\nwhich confirm DNSSEC validity.\n\nThe validation is done with the following command: `dig \u003cdomain\u003e ds`,\nwhere `\u003cdomain\u003e` corresponds to the requested domain, already sanitized.\nPlease make sure your system has the `dig` command!\nThis is typically provided by `bind9-dnsutils` or `bind-tools`.\n\nThe results are then displayed on top of the records table,\nshowing a white check mark on a green background (✅),\nor a white cross on a red background (❎),\nfollowed, respectively, by **DNSSEC OK**, or **DNSSEC FAIL**.\n\n### AbuseIPDB\nThis Middleware, written by me, checks if the incoming IP address comes from\na \"bad\" server (crawlers, scanners, etc.), thanks to\n[AbuseIPDB](https://www.abuseipdb.com/faq.html)'s `/check` API endpoint.\n\nWhen a request is received, the `BlockRequest` Middleware will check the cache,\nusing the incoming IP as key. If a record is found, check if it is a good IP:\nif it is, proceed with the request. If it isn't, throw a `403`, which will be\nrendered with a pretty page, regardless.\n\nIf no records are found in the cache, `BlockRequest` queries AbuseIPDB,\nhonoring the user-provided options (see below). If the IP address is\nwhitelisted, check if the user wants to ignore this whitelist;\nwe then check the IP score and, if it is above a certain threshold,\nthe request will be blocked, like the case above, throwing a `403`.\n\nTo use this, create an account, then head over to [AbuseIPDB/api](https://www.abuseipdb.com/account/api)\nand create an APIv2 key. Save this key into the `.env` file:\n\n```env\n# If you want to block incoming requests from bad servers\n# using AbuseIPDB, enter your API key here.\nABUSEIPDB_KEY= # Your API key goes here!\n```\n\nYou're all set! Make sure the cache store is also properly configured.\nThe cache store provided with this site is `file`, so you should be good.\n\nAdditionally, you can tune the following parameters:\n- `ABUSEIPDB_THRESHOLD`: The minimum percentage score required\n                         for an IP to be considered malicious. Default: `35`.\n- `ABUSEIPDB_IGNORE_WHITELIST`: Ignore AbuseIPDB's whitelist preference\n                                for every IP. Default: `0`.\n- `ABUSEIPDB_CACHE_TTL`: Store the results in cache for x minutes. Default: `15`\n- `ABUSEIPDB_IP_OK`: Store this string for a known good IP. Default: `OK`\n- `ABUSEIPDB_IP_BAD`: Store this string for a known bad IP. Default: `BAD`\n\n### CheckRequest Middleware\nThis Middleware, written by me, checks if the incoming request method and/or path\nare disallowed. If they are, a zip bomb is sent to the client.\n\nNote that this is employed only for those pesky bots \u0026 vulnerability scanners.\nNormal browsing will not be affected at all.\n\nIf you plan on using this middleware, make sure you take a look at\nthe `paths` array in `config/checkrequest.php`!\n\n### Rate limiter\nThis website uses Laravel's [rate limiter](https://laravel.com/docs/11.x/rate-limiting).\nIt uses the same `CACHE_STORE` driver as the AbuseIPDB integration \u0026 CheckRequest middleware,\nwhich default to `file`.\n\nThe rate limiter is defined in `app/Providers/AppServiceProvider.php` as follows:\n\n```php\n/* Bootstrap any application services. */\npublic function boot()\n{\n\t// Limit to 5 requests per minute.\n\tRateLimiter::for('global', function (Request $request) {\n\t\tif (config('APP_ENV') == 'production') {\n\t\t\treturn Limit::perMinute(5)-\u003eby($request-\u003eip());\n\t\t}\n\t});\n}\n```\n\nIt is configured to allow a maximum of **5 page requests per minute**,\nbefore throwing an HTTP 429 (Too many requests).\n\n### Asset bundling\nAssets are bundled and handled by Vite:\n- CSS \u0026 JS files are minified (PostCSS and PurgeCSS) and versioned\n- Images are versioned\n\nThis helps with removing unused code, lowering asset size, and lowering page load times.\n\nRun `npm run build` to re-generate the asset bundle.\n\n### Components\nMost HTML components (Card, Hero, Tile, etc.) are split up in several files, under `resources/views/components/`.\nThis makes it way easier and faster to write new pages, thanks to Blade Templates.\n\n### Caching\nConfig, events, views, and routes are cached, making site load-times faster.\n\nRun `composer cache` to cache them.\n\n### Minification\nEvery page is minified. Laravel does not do this by default, and there does not\nseem to be a \"standard\" way to do it, other than downloading some shady package.\n\nI've implemented my own simple HTML minifier, making use of PHP's output buffering.\n\nAdditionally, CSS \u0026 JS files are minified by PurgeCSS and Vite, respectively.\n\n## Dependencies\nTo deploy this website, you need the following:\n- `php`\n- `composer`\n- `nodejs` with `npm`\n\n## Setup\n- Clone the repo: `git clone https://github.com/saloniamatteo/openalias`\n- Change directory: `cd openalias`\n- Install PHP dependencies: `composer install`\n- Install node dependencies: `npm i`\n- Generate `APP_KEY`: `php artisan key:generate`\n\nNote that you also may need to change file permissions and/or owner\ndepending on your setup. If you do, run the following command:\n\n```bash\ngit config core.fileMode false\n```\n\nThis stops git from tracking file permission changes.\n\nIf you want to deploy the website locally, copy `.env.example` to `.env`:\n\n```bash\ncp .env.example .env\n```\n\nMake sure you modify `.env`, and uncomment the following:\n\n```env\n# Uncomment these values if running locally\nAPP_ENV=local\nAPP_DEBUG=true\nAPP_URL=\"http://localhost\"\n```\n\nThe website can now be deployed using the built-in webserver, `php artisan serve`:\nit will be reachable at `localhost` on port `8000`.\n\nIf you want to use the built-in webserver, make sure you set `APP_URL` to your website's URL.\n\nIf you want to serve this website to the Internet, please make sure you don't use\n`php spark serve`, and rather have a real server.\nI use [nginx](https://nginx.org) with [FastCGI](https://nginx.org/en/docs/http/ngx_http_fastcgi_module.html).\n\nMake sure you also disable access to `/build/assets/manifest.json`!\n\nWhen updating, you may use the `update.sh` script under the `scripts/` folder:\n\n```bash\n./scripts/update.sh\n```\n\nThis does the following:\n- Installs the composer + npm dependencies\n- Generates a new key, forcefully\n- Bundles the assets\n- Caches config, events, routes, views.\n\n### Assets\nMake sure you bundle the assets used in the website (CSS, fonts, images):\n\n```sh\nnpm run build\n```\n\n### Cache\nWhen running in production, it is recommended to cache PHP assets with the following command:\n\n```sh\ncomposer cache\n```\n\nThis will cache PHP config, events, routes, views.\n\n### Sample nginx config\nNote: this config makes the following assumptions:\n- Your site is hosted at `oa.example.com`\n- You use LetsEncrypt (`certbot`) and have deployed an SSL certificate\n- Your `nginx` build supports HTTP2 and HTTP3 (QUIC)\n- You have IPv6 support enabled\n- You use port 80 for HTTP and port 443 for HTTPS\n- You use php-fpm (FastCGI) and call it via `/var/run/php-fpm.sock`\n- You want to disable client uploads\n- You want to redirect every HTTP request to the HTTPS port\n- You want to allow `robots.txt`\n- You want to disable `.well-known`\n\nMake sure you movify everything that says \"Change this\"!\n\n```nginx\n# Optional: Rate-limits\n#limit_req_zone $binary_remote_addr zone=oa_css:10m rate=10r/s;\n#limit_req_zone $binary_remote_addr zone=oa_img:10m rate=5r/s;\n\n# Optional: Bandwidth limits\n#limit_conn_zone $binary_remote_addr zone=oa_conn_css:10m;\n#limit_conn_zone $binary_remote_addr zone=oa_conn_img:10m;\n\nserver {\n\t# HTTP/1.1 \u0026 HTTP/2\n\tlisten 443 ssl;\n\tlisten [::]:443 ssl;\n\n\t# HTTP/3 (QUIC)\n\tlisten 443 quic;\n\tlisten [::]:443 quic;\n\n\t# Change this!\n\tserver_name oa.example.com;\n\n\t# If the host isn't oa.example.com, redirect the client\n\tif ($host != oa.example.com) {\n\t\treturn 301 https://oa.example.com$request_uri;\n\t}\n\n\t# HTTP2/3\n\thttp2 on;\n\thttp3 on;\n\tquic_gso on;\n\tquic_retry on;\n\tssl_early_data on;\n\n\t# SSL\n\tssl_stapling on;\n\tssl_stapling_verify on;\n\tinclude /etc/letsencrypt/options-ssl-nginx.conf;\n    ssl_certificate /etc/letsencrypt/live/oa.example.com/fullchain.pem; # Change this!\n    ssl_certificate_key /etc/letsencrypt/live/oa.example.com/privkey.pem; # Change this!\n\tssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;\n\n\t# Site root\n\t# Change this!\n\troot /var/www/oa/public;\n\n\t# Prevent nginx HTTP Server Detection\n\tserver_tokens off;\n\n\t# Only allow GET requests\n\tif ($request_method !~* ^GET$) {\n\t\treturn 405;\n\t}\n\n\t# Disable uploads\n\tclient_max_body_size 0;\n\tclient_body_timeout 0s;\n\tfastcgi_buffers 64 4K;\n\n\t# The settings allows you to optimize the HTTP2 bandwidth.\n\t# See https://blog.cloudflare.com/delivering-http-2-upload-speed-improvements for tuning hints\n\tclient_body_buffer_size 512k;\n\n\t# Specify how to handle directories -- specifying `/index.php$request_uri`\n\t# here as the fallback means that Nginx always exhibits the desired behaviour\n\t# when a client requests a path that corresponds to a directory that exists\n\t# on the server. In particular, if that directory contains an index.php file,\n\t# that file is correctly served; if it doesn't, then the request is passed to\n\t# the front-end controller. This consistent behaviour means that we don't need\n\t# to specify custom rules for certain paths (e.g. images and other assets,\n\t# `/updater`, `/ocm-provider`, `/ocs-provider`), and thus\n\t# `try_files $uri $uri/ /index.php$request_uri`\n\t# always provides the desired behaviour.\n\tindex index.php index.html /index.php$request_uri;\n\n\t# Allow robots.txt\n\tlocation = /robots.txt {\n\t\tallow all;\n\t\tlog_not_found off;\n\t}\n\n\t# Allow .well-known/security.txt\n\tlocation = /.well-known/security.txt {\n\t\tallow all;\n\t\tlog_not_found off;\n\t}\n\n\t# Prepend all requests with \"/index.php\" -- this acts as our front controller.\n\t# index.php handles all requests, but we have to hide it.\n\t# The line below allows us to do exactly what we want.\n\tlocation / {\n\t\trewrite ^ /index.php;\n    }\n\n\t# Ensure this block, which passes PHP files to the PHP process, is above the blocks\n\t# which handle static assets (as seen below). If this block is not declared first,\n\t# then Nginx will encounter an infinite rewriting loop when it prepends `/index.php`\n\t# to the URI, resulting in a HTTP 500 error response.\n\tlocation ~ \\.php(?:$|/) {\n\t\tfastcgi_split_path_info ^(.+?\\.php)(/.*)$;\n\t\tset $path_info $fastcgi_path_info;\n\n\t\t# Try to load requested file. If it doesn't exist, instead\n\t\t# of throwing a 404, load the front controller, where\n\t\t# we can load a pretty 404 page.\n\t\ttry_files $fastcgi_script_name /index.php/$fastcgi_script_name;\n\n\t\tinclude fastcgi_params;\n\t\tfastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;\n\t\tfastcgi_param PATH_INFO $path_info;\n\t\tfastcgi_param HTTPS on;\n\n\t\tfastcgi_param modHeadersAvailable true;\t\t # Avoid sending the security headers twice\n\t\tfastcgi_param front_controller_active true;\t # Enable pretty urls\n\t\tfastcgi_pass unix:/var/run/php-fpm.sock;\n\n\t\tfastcgi_intercept_errors on;\n\t\tfastcgi_request_buffering off;\n\t\tfastcgi_max_temp_file_size 0;\n\n\t\t# Remove X-Powered-By, which is an information leak\n\t\tfastcgi_hide_header X-Powered-By;\n\n\t\t# Do not show ratelimit\n\t\tfastcgi_hide_header X-Ratelimit-Limit;\n\t\tfastcgi_hide_header X-Ratelimit-Remaining;\n\n\t\t# Enable gzip but do not remove ETag headers\n\t\tgzip on;\n\t\tgzip_vary on;\n\t\tgzip_comp_level 4;\n\t\tgzip_min_length 256;\n\t\tgzip_proxied expired no-cache no-store private no_last_modified no_etag auth;\n\t\tgzip_types text/plain;\n\n\t\t# Inform clients that HTTP3 is available\n\t\tadd_header Alt-Svc 'h3=\":443\"; ma=86400';\n\n\t\t# COOP/COEP. Disable if you use external plugins/images/assets\n\t\tadd_header Cross-Origin-Opener-Policy \"same-origin\" always;\n\t\tadd_header Cross-Origin-Embedder-Policy \"require-corp\" always;\n\t\tadd_header Cross-Origin-Resource-Policy \"same-origin\" always;\n\n\t\t# Content Security Policy\n\t\t# See: https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP\n\t\t# This policy allows only internal assets.\n\t\tadd_header Content-Security-Policy \"default-src 'self'; img-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; child-src 'self';\";\n\n\t\t# HSTS\n\t\tadd_header Strict-Transport-Security \"max-age=31536000; includeSubDomains; preload\" always;\n\n\t\t# HTTP response headers borrowed from Nextcloud `.htaccess`\n\t\tadd_header Referrer-Policy \"no-referrer\";\n\t\tadd_header X-Content-Type-Options \"nosniff\";\n\t\tadd_header X-Download-Options \"noopen\";\n\t\tadd_header X-Frame-Options \"SAMEORIGIN\";\n\t\tadd_header X-Permitted-Cross-Domain-Policies \"none\";\n\t\tadd_header X-XSS-Protection \"0\";\n\n\t\t# Tell browsers to use per-origin process isolation\n\t\tadd_header Origin-Agent-Cluster \"?1\" always;\n\t}\n\n\t# CSS \u0026 JS\n\tlocation ~ \\.(?:css|js|woff2)$ {\n\t\t# Limit access to CSS \u0026 JS\n\t\t# Set a burst of 15, and start delaying after the 10th req.\n\t\t#limit_req zone=oa_css burst=15 delay=10;\n\t\t#limit_req_log_level warn;\n\t\t#limit_req_status 429;\n\n\t\t# Cap bandwidth to 1MB/s after 1MB,\n\t\t# allowing 5 concurrent requests\n\t\t#limit_conn oa_conn_css 5;\n\t\t#limit_rate_after 1M;\n\t\t#limit_rate 1M;\n\n\t\t# Enable gzip but do not remove ETag headers\n\t\tgzip on;\n\t\tgzip_vary on;\n\t\tgzip_comp_level 4;\n\t\tgzip_min_length 256;\n\t\tgzip_proxied expired no-cache no-store private no_last_modified no_etag auth;\n\t\tgzip_types font/woff2 text/css text/javascript text/plain;\n\n\t\tadd_header Alt-Svc 'h3=\":443\"; ma=86400';\n\t\tadd_header X-Content-Type-Options \"nosniff\";\n\t\tadd_header X-Frame-Options \"SAMEORIGIN\";\n\t\tadd_header Strict-Transport-Security \"max-age=31536000; includeSubDomains; preload\" always;\n\n\t\ttry_files $uri /index.php$request_uri;\n\n\t\texpires 10d;\n\t\taccess_log off;\n\t}\n\n\t# Images\n\tlocation ~ \\.(?:gif|ico|jpg|jpeg|pdf|png|svg|webp)$ {\n\t\t# Limit access to images\n\t\t# Set a burst of 10, and start delaying after the 5th req.\n\t\t#limit_req zone=oa_img burst=10 delay=5;\n\t\t#limit_req_log_level warn;\n\t\t#limit_req_status 429;\n\n\t\t# Cap bandwidth to 1MB/s after 1MB,\n\t\t# allowing 5 concurrent requests\n\t\t#limit_conn oa_conn_img 5;\n\t\t#limit_rate_after 1M;\n\t\t#limit_rate 1M;\n\n\t\tadd_header Alt-Svc 'h3=\":443\"; ma=86400';\n\t\tadd_header X-Content-Type-Options \"nosniff\";\n\t\tadd_header X-Frame-Options \"SAMEORIGIN\";\n\t\tadd_header Strict-Transport-Security \"max-age=31536000; includeSubDomains; preload\" always;\n\n\t\ttry_files $uri /index.php$request_uri;\n\n\t\texpires 14d;\n\t\taccess_log off;\n\t}\n}\n\nserver {\n\tlisten 80;\n\tlisten [::]:80;\n\n\t# Change this!\n\tserver_name oa.example.com;\n\n\t# Prevent nginx HTTP Server Detection\n\tserver_tokens off;\n\n\t# Change this!\n\treturn 301 https://oa.example.com$request_uri;\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsaloniamatteo%2Fopenalias","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsaloniamatteo%2Fopenalias","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsaloniamatteo%2Fopenalias/lists"}