ConfirmByKeyTrait
Confirms a record by its author with the key from the e-mail; shared logic for an advert (Bazaar), a company profile (Comcat) and a discussion post.
The e-mail with the link ?do=confirm&key=… is sent by the Api manager on insert when the module
requires confirmation from the given kind of author (EmailConfirmationSetting).
Security rests on the key (256 bits, only a digest in the database, AdvertConfirmationKey),
not on a login, like account activation
(UserManager::activateUser()); a guest author clicks the link too.
Contract of self::confirmByKey():
- an unknown, deleted or banned record, an empty or wrong key and an exhausted limit give one answer
(
confirmationKeyInvalidCode()of the host; no oracle on the existence or state of a record), - a correct key of an unconfirmed record sets
confirmedAt = now, consumes the key (only a "consumed" digest stays in the database, which confirms nothing anymore) and then runs the follow-ups (afterRecordConfirmed()of the host), - an already confirmed record with a correct key succeeds without change (a repeated click from the mailbox is not an error); with a wrong key it gives the same error as above,
- limit: failed attempts per record and per IP (
ratelimit.advertConfirm, shared by all modules, limit keys separated by module); a correct key does not spend the quota. Once exhausted, even a correct key is rejected until the window expires.
No e-mail is sent after the confirmation.
Requires in the using class:
$this->rateLimit(RateLimit),$this->rateLimitConfig(RateLimitConfig),findRecordForConfirmation(int), the Shared advert, profile or post entity ornull, read fresh from the database (without the query cache a consumed key could be used again),updateConfirmationColumns(int, array): Result, a write through the Api manager (cache bump),afterRecordConfirmed(int): void, the follow-ups after the write (search index, category counts...),getConfirmModule(): string(bazaar|comcat|discussion), used only in limit keys and the log,confirmationKeyInvalidCode(): ResultCode, the code of the uniform error answer.
Advert modules use it through AdvertConfirmByKeyTrait (hook names kept).
Table of Contents
Constants
- CONFIRM_KEY_MAX_LENGTH : int = 128
- Input longer than any issued key is not even looked up (64 hex characters).
Methods
- confirmByKey() : Result
- confirmIpLimitKey() : string
- confirmRecordLimitKey() : string
- The limit keys keep the format from when the trait knew only adverts (`advert-confirm:<module>:advert:<id>`).
- passesConfirmLimit() : bool
- Peeks without incrementing: only failed attempts spend the quota ({@see self::rejectConfirmation()}).
- rejectConfirmation() : Result
Constants
CONFIRM_KEY_MAX_LENGTH
Input longer than any issued key is not even looked up (64 hex characters).
private
int
CONFIRM_KEY_MAX_LENGTH
= 128
Methods
confirmByKey()
public
confirmByKey(int $id, string $key, string|null $ip) : Result
Parameters
- $id : int
- $key : string
- $ip : string|null
Return values
ResultconfirmIpLimitKey()
private
confirmIpLimitKey(string|null $ip) : string
Parameters
- $ip : string|null
Return values
stringconfirmRecordLimitKey()
The limit keys keep the format from when the trait knew only adverts (`advert-confirm:<module>:advert:<id>`).
private
confirmRecordLimitKey(int $id) : string
Parameters
- $id : int
Return values
stringpassesConfirmLimit()
Peeks without incrementing: only failed attempts spend the quota ({@see self::rejectConfirmation()}).
private
passesConfirmLimit(int $id, string|null $ip) : bool
Parameters
- $id : int
- $ip : string|null
Return values
boolrejectConfirmation()
private
rejectConfirmation(int $id, string|null $ip) : Result
Parameters
- $id : int
- $ip : string|null