=== Nielco IT Login & Enumeration Hardening ===
Contributors: nielcoit
Author: Nielco IT
Author URI: https://nielcoit.dk
Plugin URI: https://nielcoit.dk
Tags: security, hardening, xmlrpc, enumeration, rest api
Requires at least: 5.5
Tested up to: 6.8
Requires PHP: 7.4
Stable tag: 2.0.3
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Lukker de enumeration- og autentificeringsflader, som et skjult login ikke
beskytter. Afgrænsede WordPress-hooks uden persistent tilstand. Udviklet af Nielco IT.

== Beskrivelse ==

Et skjult login kan reducere støj fra simple bots. Det lukker ikke WordPress'
øvrige autentificerings- og identitetsflader. Dette plugin lukker udvalgte af
de core-baserede flader.

Pluginnet er bevidst afgrænset til afgrænsede WordPress-hooks uden persistent
tilstand: ingen tællere, transients eller IP-håndtering. Author-normaliseringen
bruger en request-lokal markør, men intet gemmes mellem requests. Det gør laget
forudsigeligt og svært at få galt i halsen.

OMFATTEDE FLADER:
1. XML-RPC: deaktiverer autentificerede metoder og fjerner core-pingback samt
   X-Pingback. Lukker ikke hele xmlrpc.php (gør det på server-/CDN-/WAF-niveau).
2. REST user-endpoint (/wp-json/wp/v2/users) for uindloggede. Fordi selve ruten
   afregistreres, dækkes både /wp-json/ og ?rest_route=, både collection og
   enkelt-ID, samt search_columns-oraklet.
3. Author-enumeration: ?author=N, ?author_name= og /author/ normaliseres på
   'request'-filteret FØR hovedqueryen til en tom 404 uden feed. Kendte og
   ukendte slugs ender i samme tomme resultat, og author-feeds udsendes ikke.
4. Forfatterdata i oEmbed-svar.
5. Author-provider i core-sitemap (både pæn URL og query-form afregistreres).
6. RSS/Atom-feeds: forfatternavnet erstattes med "Anonym" (fjerner ikke alle
   forfatterfelter; andre felter kan bestå, jf. afgrænsningen nedenfor).
7. Login-fejl: kun enumeration-relevante koder (invalid_username,
   invalid_email, incorrect_password) generaliseres via wp_login_errors.
   Drifts- og cookie-fejl bevares.
8. Admin-advarsel på brugeroversigten hvis visningsnavn = login-navn (op til
   200 konti undersøges, hvilket beskeden oplyser).

== Bevidst udeladt ==

Pluginnet indeholder IKKE brute force-spærring, CAPTCHA, request-filter eller
malware-scanning. De hører til på infrastruktur-niveau (rate limiting og WAF på
CDN eller webserver) eller i dedikerede værktøjer, og de kan i et let plugin
ikke gøres robuste uden race conditions og falsk tryghed. Kombiner dette plugin
med to-faktor og en WAF.

== Hvad pluginnet ikke lukker ==

- Password-reset-oraklet (retrieve_password afslører kendte konti/mails). Nogle
  hide-login-plugins flytter reset-flowet; test det separat.
- Forfattermetadata eksponeret af temaer eller andre plugins.
- Custom REST- eller login-ruter.
- Auth-flader, hvis XML-RPC eller Application Passwords genaktiveres.
- Enumeration for INDLOGGEDE brugere. REST- og author-kontrollen springer alle
  indloggede over, så redaktionelle funktioner ikke brydes. På et site med åben
  registrering kan en abonnentkonto derfor nå de offentlige forfatterruter. En
  strengere, capability-baseret tilstand er bevidst udeladt, da den skal testes
  mod blokeditor og medlems-/webshop-plugins for ikke at bryde workflows.

== Installation ==

1. Upload zip under Plugins > Tilføj nyt > Upload, eller læg mappen
   nielco-login-hardening i wp-content/plugins/.
2. Aktiver. Alle flader lukkes som standard.

Must-use-variant: læg nielco-login-hardening.php i wp-content/mu-plugins/, så en
kompromitteret admin ikke kan deaktivere det. Bemærk: opdateringer bliver
manuelle. Kildesproget er dansk, så danske sites påvirkes ikke, men oversættelser
til andre sprog indlæses ikke i MU-varianten (det kræver load_muplugin_textdomain
eller en loader i roden af mu-plugins, der inkluderer hele pluginmappen).
Pluginnet har ingen aktiverings- eller deaktiveringstilstand at rydde.

== Konfiguration (wp-config.php) ==

Hold en flade åben, hvis sitet reelt bruger den (alle default = luk fladen):

    define( 'NIELCO_DISABLE_XMLRPC', false );        // hvis en app kræver XML-RPC
    define( 'NIELCO_DISABLE_APP_PASSWORDS', false );  // hvis en integration bruger det
    define( 'NIELCO_STRIP_FEED_AUTHOR', false );      // hvis feeds skal vise forfatter
    define( 'NIELCO_WARN_DISPLAY_NAME', false );      // slå admin-advarslen fra

== Licens ==

Copyright 2026 Nielco IT (https://nielcoit.dk).

Distribueres under GPL-2.0-or-later. Ved videredistribution skal eksisterende
copyright- og licensmeddelelser i kildekoden bevares. Se
https://www.gnu.org/licenses/gpl-2.0.html.

== Testmatrix før stabil frigivelse ==

Kør på en levende WordPress 7.0.2-installation (single-site, PHP 7.4 og en
aktuel PHP-version, standardtema samt et tema uden 404.php, pæne og plain
permalinks). Bump "Tested up to" til 7.0.2, når matricen består:

- Standardlogin uden pluginet aktivt vs. aktivt: uændret adfærd.
- /wp-json/wp/v2/users og ?rest_route=/wp/v2/users: fjernet for uindloggede.
- Kendt vs. ukendt author-slug: samme status, headers og body.
- oEmbed, author-sitemap (pæn URL og query-form), feeds: forfatter fjernet.
- XML-RPC autentificeret metode: afvist.
- Application Password: afvist mens funktionen er deaktiveret.
- Login med forkert brugernavn vs. gyldigt brugernavn og forkert password:
  samme generiske besked.

== Changelog ==

= 2.0.3 =
* Ikke-skalære author- og author_name-værdier (fx ?author[]=1) lukkes nu
  fail-closed til samme tomme 404 i stedet for at nå core.
* Håndhævende filtre kører nu på høj prioritet, så en anden plugins tidligere
  filter ikke kan genindsætte author-, feed- eller REST-data efter os.
* Beskrivelse strammet til "udvalgte core-baserede flader".
* Dokumenteret at indloggede lavprivilegerede brugere bevidst ikke blokeres.

= 2.0.2 =
* Author-blokering flyttet til 'request'-filteret, så den kører FØR hovedqueryen.
  Lukker author-feed-omgåelsen (/author/slug/feed/), hvor set_404() på
  template_redirect bevarede is_feed og stadig udsendte feedet.
* Login-fejl muteres nu på det eksisterende WP_Error, så øvrige fejls data
  bevares (tidligere rekonstruktion tabte fejldata).
* Præciserede formuleringer: "uden persistent tilstand" frem for "uden tilstand",
  afgrænsede hooks frem for "enkelt filter", samlet sikkerhedsopstilling frem
  for "fuld dækning". MU-oversættelsesnote tilføjet.

= 2.0.1 =
* Author-blokering rydder nu også author-query-vars (forsvar mod at et tema
  genudleder forfatteren efter set_404).
* Feed-forfatter returnerer et generisk navn i stedet for tom streng, så feeds
  ikke får tomme forfatter-elementer.
* Note: esc_html( _n() ) er bevaret bevidst. esc_html_n() findes ikke i core.

= 2.0.0 =
* Afgrænset til rent deklarativt enumeration- og auth-flade-lag.
* Fjernet brute force, CAPTCHA, request-filter og indikatorsøgning. De var
  kilden til race conditions og falsk tryghed og hører til på anden hylde.
* Author-blokering: ens 404 uden manuelt template-include eller exit.
* Login-fejl: kun enumeration-relevante koder generaliseres via wp_login_errors.
* Visningsnavn-advarsel kun på brugeroversigten. Blødere formulering.
* Tekstdomæne matcher slug (nielco-login-hardening).

= 1.x =
* Tidligere brede versioner med beskyttelseslag. Udfaset.
