Framework

Repository Author Commit message Committed SHA  
 
security by dg User: authorization is decided by voters instead of an authorizator per role (BC break)

A Voter decides about a Principal, the effective state of the user: the
identity only while logged in (unlike User::getId(), which keeps returning
the retained identity after logout), the effective roles and the voters,
so that a voter may delegate through $principal->isAllowed(). Ownership is
checked by Principal::hasId(), which never matches for a guest. A vote is
a Vote: a single Forbid wins, otherwise a single Allow suffices.
Vote::allowIf() allows or abstains, so forbidding is always written on
purpose. User::createPrincipal() decides about someone else than the
current user, or about a visitor for null, taking the identity as it is;
getPrincipal() is built on it.

Permission is one of the voters; its vote() ORs the roles, forbids when
an explicit deny rule stopped them and abstains when only the default
deny-all did, as well as on roles and resources the ACL does not know
instead of throwing.

SecurityExtension adds every service implementing Voter to the user.
setAuthorizator() and the getters are deprecated; the third parameter of
the User constructor is a variadic list of voters, User::isAllowed() types
the privilege as ?string.

security by dg Role is deprecated, the core works with role names only (BC break)

Roles are names. An identity returning a Role object throws
InvalidStateException, Permission::isAllowed() accepts the role only as a
string, and getQueriedRole() and getQueriedResource() return names, so an
assertion decides by names only.

Resource stays: it maps an entity to the name of an ACL resource, so the
rules of that resource apply to the entity.

security by dg deprecated wip
security by dg CookieIdentity WIP
security by dg IdentityHandler: make getGuestIdentity() a regular interface method (BC break)

Promotes the optional @method to a required method, so User no longer needs method_exists() to call it. BC break: existing IdentityHandler implementations must now declare getGuestIdentity().

security by dg User: deprecated magic properties (BC break)
security by dg SimpleIdentity: reading an undeclared property throws (BC break)

Until now __get() returned null for an unknown key and, because it returns
by reference, silently created that key in the data (and thus in the storage).
It now throws MemberAccessException, like any other Nette object.

This also ends the by-ref write pattern $identity->cart[] = $item on a key
that has not been set yet.

security by dg SimpleIdentity: uses __serialize & __unserialize
security by dg IIdentity: make getData() a regular interface method (BC break)
mail by dg Message: Message-ID takes the domain of the sender

The domain came from $_SERVER['HTTP_HOST'] or php_uname(), i.e. from a header
the client controls (with a port it turned into example.com8080) or from the
name of the machine, which in CLI and containers is a random string, neither
of which says where the message comes from. The domain is now taken from the
Sender address, or from From, the way other mail libraries do it; the old
source remains for a message with neither, and for an internationalized domain
left unconverted without ext-intl.

mail by dg MailPanel: previews the body and attachments of each message

The panel listed only the envelope, so checking what a message actually looked
like meant sending it somewhere first. Each message now has a collapsed preview:
the HTML body in a sandboxed iframe, the text body, and the attachments by name,
type and size. Embedded images are referenced by cid:, which means nothing to a
browser, so they are inlined as data: URIs and the preview shows what the
recipient sees.

Message::getEmbeddedFiles() exposes the embedded parts, the counterpart of
getAttachments().

mail by dg CssInliner: writes every candidate of a property, the winner last

Email CSS leans on fallbacks: display: -webkit-box; display: flex works because a
client drops a value it does not understand and the previous declaration applies.
Writing only the cascade winner left an old client with nothing. The commonest
case, a fallback within one rule, was lost even earlier, in parsing, which kept
the declarations of a block in a property => value map.

A block keeps its duplicate properties, and inline() writes all candidates of a
property ordered by rank, the winner last, so the client resolves the rest the
way a browser would, fallbacks across rules included. A candidate whose value a
higher-ranked one repeats is dropped, since it can never matter. getRules()
keeps its shape and returns the last value of each property.

mail by dg MailExtension: the accessToken key enables XOAUTH2

Setting an access token meant a setup: entry on the transport service, whose
name is mail.mailer or mail.innerMailer depending on whether redirect or the
debugger is on. The accessToken key passes the token to setAccessToken() on
whichever it is. It takes anything DI evaluates; the useful form is a callable
such as @App\GoogleOAuth::getAccessToken(...), resolved on every connection so
an expiring token gets refreshed.

A token configured without the SMTP transport is a configuration error rather
than silently ignored.

mail by dg MailExtension: the file key writes emails to .eml files

FileMailer could only be used by registering mail.mailer by hand, which also gave
up everything the extension wires around the transport: the DKIM signer, the
Interceptor for redirect and debugger, and the Tracy panel. For development that
is the configuration people want first.

With `file: <dir>` the transport is FileMailer, taking precedence over smtp and
sendmail, and the rest is wired around it as for any other transport.

mail by dg SmtpMailer: rejects an unknown encryption (BC break)

Any value of encryption other than 'ssl' or 'tls' was silently treated as
none, so 'TLS', 'SSL' or 'starttls' connected without encryption to port 25.
Depending on the server, sending then failed with a misleading "does not
support authentication", or the credentials and the message went out in plain
text. The DI schema does not catch it when the value comes from a dynamic
parameter such as %env%. The constructor now throws InvalidArgumentException,
so a configuration that used to send unencrypted fails instead.

tracy by dg used attribute Deprecated
tracy by dg error.log changed to warning.log
tracy by dg Logger: added typehints WIP
tracy by dg open in editor: added support for columns
tracy by dg opened 3.0-dev
security by dg Identity -> SimpleIdentity

Identity class must exist as an alias in order to read it from session

security by dg IIdentity: added return typehint (BC break)
security by dg removed deprecated IAuthenticator (BC break)
security by dg removed legacy services names (BC break)
security by dg used PHP 8.2 features
security by dg uses nette/http 4
security by dg requires PHP 8.3
security by dg opened 4.0-dev
security by dg uses dresscode
security by dg Permission: fixed whole-resource query ignoring a privilege deny on a parent resource
forms by dg BaseControl: added setFixedValue() for a value the user cannot change
forms by dg netteForms: removed webalize() (BC break)

Last synchronization: 2026-10-28 22:03:00