generateUserSessionKey() built its AES-128 key with randomString(16), which
draws 12 random bytes and base64url-encodes them into 16 printable characters.
Those 16 characters were handed to openssl_encrypt as the 16-byte key, so the
key that wraps the site master key in the user's session carried 96 bits of
entropy instead of 128. Same for the IV.
The key and IV are now random_bytes(16) and stay raw for the cipher. Base64 is
applied only for transport - the cookie and the session copy of the IV - and
decoded again at the three read sites.
Sessions issued before this change will not decode and are not supported;
anyone logged in at deploy time is prompted to log in again. Nothing is stored
long term in this path, so there is nothing to migrate.
Also guards encryptCredentialEntry against a master key that failed to decrypt.
openssl_encrypt accepts false as a key and silently encrypts under an empty
key, so a session whose cookie had expired could write a credential that no
key would ever recover. It now returns false instead. This was reachable
before this change too, whenever a cookie expired mid-session.
Return 403 on CSRF failure instead of a 302, which anything following
redirects records as a 200. Set SameSite=Lax at every session_start;
keepalive.php and guest_post.php had no cookie flags at all.
getDnsRecords and getDomainExpirationDate had regressed to shell_exec
(dig/whois) when domain code was moved into functions/domain.php; the
RDAP helper stack was dropped entirely. Restores the dns_get_record +
RDAP + port-43-socket-whois implementation from d1e1609b under the
current function names. getSslCertificate was unaffected.
Replace md5(file_contents)+randomString(2) naming with randomString(32).
No longer reads the file into memory (removes file_get_contents), so
validation is O(1) regardless of size or upload count. Add is_uploaded_file()
and UPLOAD_ERR_OK checks, use pathinfo() for extension extraction, and
return false consistently on all failures (oversize previously returned a
truthy error string that callers treated as a valid filename).
Replace srand()/rand() with random_int() for cryptographically secure,
unbiased key generation. The previous implementation seeded rand() from
microtime(), making TOTP secrets predictable if the generation time
could be approximated. Also removes modulo bias and dead while(1)
wrapper.
Output format is unchanged: 32 chars from the base32 alphabet (A-Z,
2-7), so existing TOTP enrollments are unaffected.