Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@
class Application extends App implements IBootstrap {
public const APP_ID = 'suspicious_login';

/** @psalm-mutation-free */
public function __construct(array $urlParams = []) {
parent::__construct(self::APP_ID, $urlParams);

Check failure on line 28 in lib/AppInfo/Application.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

ImpureMethodCall

lib/AppInfo/Application.php:28:3: ImpureMethodCall: The context allows only reading and mutating instance state but method is impure (see https://psalm.dev/203)
}

#[\Override]
Expand All @@ -39,6 +40,6 @@
}

#[\Override]
public function boot(IBootContext $context): void {

Check failure on line 43 in lib/AppInfo/Application.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

MissingPureAnnotation

lib/AppInfo/Application.php:43:18: MissingPureAnnotation: boot must be marked @psalm-mutation-free to aid security analysis, run with --alter --issues=MissingPureAnnotation to fix this (see https://psalm.dev/363)
}
}
1 change: 1 addition & 0 deletions lib/Command/ETL.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/** @psalm-immutable */
class ETL extends Command {

public function __construct(
Expand Down
1 change: 1 addition & 0 deletions lib/Command/Optimize.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use function extension_loaded;
use function time;

/** @psalm-immutable */
class Optimize extends Command {
use ModelStatistics;

Expand Down
1 change: 1 addition & 0 deletions lib/Command/Predict.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/** @psalm-immutable */
class Predict extends Command {

public function __construct(
Expand Down
1 change: 1 addition & 0 deletions lib/Command/Seed.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/** @psalm-immutable */
class Seed extends Command {
use ModelStatistics;

Expand Down
1 change: 1 addition & 0 deletions lib/Command/Train.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
use function extension_loaded;
use function time;

/** @psalm-immutable */
class Train extends Command {
use ModelStatistics;

Expand Down
1 change: 1 addition & 0 deletions lib/Db/LoginAddressAggregatedSeeder.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class LoginAddressAggregatedSeeder {
/** @var IDBConnection */
private $db;

/** @psalm-mutation-free */
public function __construct(
IDBConnection $db,
private readonly LoginAddressAggregatedMapper $mapper,
Expand Down
1 change: 1 addition & 0 deletions lib/Db/Model.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ class Model extends Entity implements JsonSerializable {
protected $createdAt;
protected $addressType;

/** @psalm-mutation-free */
#[\Override]
#[ReturnTypeWillChange]
public function jsonSerialize(): array {
Expand Down
1 change: 1 addition & 0 deletions lib/Exception/InsufficientDataException.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
namespace OCA\SuspiciousLogin\Exception;

class InsufficientDataException extends ServiceException {
/** @psalm-mutation-free */
public function __construct(string $message = '') {
parent::__construct(
$message === '' ? 'Insufficient data' : "Insufficient data: $message"
Expand Down
1 change: 1 addition & 0 deletions lib/Listener/LoginListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
* @implements IEventListener<UserLoggedInEvent>
*/
class LoginListener implements IEventListener {
/** @psalm-mutation-free */
public function __construct(
private readonly IRequest $request,
private readonly ITimeFactory $timeFactory,
Expand Down
1 change: 1 addition & 0 deletions lib/Listener/LoginMailListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
*/
class LoginMailListener implements IEventListener {

/** @psalm-mutation-free */
public function __construct(
private readonly LoggerInterface $logger,
private readonly IMailer $mailer,
Expand Down
1 change: 1 addition & 0 deletions lib/Listener/LoginNotificationListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
*/
class LoginNotificationListener implements IEventListener {

/** @psalm-mutation-free */
public function __construct(
private readonly IManager $notificationManager,
private readonly ITimeFactory $timeFactory,
Expand Down
1 change: 1 addition & 0 deletions lib/Migration/Version4002Date20220922094803.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class Version4002Date20220922094803 extends SimpleMigrationStep {
*/
protected $connection;

/** @psalm-mutation-free */
public function __construct(IDBConnection $connection) {
$this->connection = $connection;
}
Expand Down
1 change: 1 addition & 0 deletions lib/Migration/Version9000Date20250114095826.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

class Version9000Date20250114095826 extends SimpleMigrationStep {

/** @psalm-mutation-free */
public function __construct(
private readonly IJobList $jobList,
) {
Expand Down
2 changes: 2 additions & 0 deletions lib/Notifications/Notifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,15 @@ class Notifier implements INotifier {
/** @var IURLGenerator */
protected $url;

/** @psalm-mutation-free */
public function __construct(IFactory $factory, IRequest $request, IConfig $config, IURLGenerator $urlGenerator) {
$this->config = $config;
$this->factory = $factory;
$this->request = $request;
$this->url = $urlGenerator;
}

/** @psalm-pure */
#[\Override]
public function getID(): string {
return Application::APP_ID;
Expand Down
8 changes: 8 additions & 0 deletions lib/Service/AClassificationStrategy.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,14 @@
use function str_split;

abstract class AClassificationStrategy {
/** @psalm-pure */
abstract public static function getTypeName(): string;

/** @psalm-impure */
abstract public function hasSufficientData(LoginAddressAggregatedMapper $loginAddressMapper, int $validationDays): bool;

/**
* @psalm-impure
* @return LoginAddressAggregated[][]
*/
abstract public function findHistoricAndRecent(LoginAddressAggregatedMapper $loginAddressMapper, int $validationThreshold, int $maxAge): array;
Expand All @@ -47,6 +50,7 @@
}

/**
* @psalm-pure
* @param string $ip
*
* @return int[]
Expand Down Expand Up @@ -74,21 +78,25 @@
* @psalm-param 10|16 $base
* @psalm-param 4|8 $padding
*/
protected function numStringsToBitArray(array $strings, int $base, int $padding): array {

Check failure on line 81 in lib/Service/AClassificationStrategy.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

MissingPureAnnotation

lib/Service/AClassificationStrategy.php:81:21: MissingPureAnnotation: numStringsToBitArray must be marked @psalm-mutation-free to aid security analysis, run with --alter --issues=MissingPureAnnotation to fix this (see https://psalm.dev/363)
$converted = array_reduce(array_map(fn (string $s) => $this->numStringToBitArray($s, $base, $padding), $strings), array_merge(...), []);
return array_map(fn ($x) => (int)$x, $converted);
}

/** @psalm-pure */
protected function numStringToBitArray(string $s, int $base, int $padding): array {
$bin = base_convert($s, $base, 2);
// make sure we get 00000000 to 11111111
$padded = str_pad($bin, $padding, '0', STR_PAD_LEFT);
return str_split($padded);
}

/** @psalm-impure */
abstract public function generateRandomIp(): string;

/** @psalm-pure */
abstract public function getSize(): int;

/** @psalm-mutation-free */
abstract public function getDefaultMlpConfig(): Config;
}
2 changes: 2 additions & 0 deletions lib/Service/CollectedData.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@

use Rubix\ML\Datasets\Labeled;

/** @psalm-immutable */
class CollectedData {
/** @psalm-mutation-free */
public function __construct(
private readonly Labeled $trainingPositives,
private readonly Labeled $validationPositives,
Expand Down
1 change: 1 addition & 0 deletions lib/Service/DataLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class DataLoader {
private const MAX_SAMPLES_POSITIVES = 15_000;
private const MAX_SAMPLES_VALIDATE_POSITIVES = 3_000;

/** @psalm-mutation-free */
public function __construct(
private readonly LoginAddressAggregatedMapper $loginAddressMapper,
private readonly NegativeSampleGenerator $negativeSampleGenerator,
Expand Down
1 change: 1 addition & 0 deletions lib/Service/ETLService.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
class ETLService {
public const MAX_BATCH_SIZE = 10000;

/** @psalm-mutation-free */
public function __construct(
private readonly IDBConnection $db,
private readonly LoginAddressAggregatedMapper $aggregatedMapper,
Expand Down
1 change: 1 addition & 0 deletions lib/Service/EstimatorService.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

class EstimatorService {

/** @psalm-mutation-free */
public function __construct(
private readonly ModelStore $modelStore,
private readonly LoggerInterface $logger,
Expand Down
4 changes: 4 additions & 0 deletions lib/Service/IpV6Strategy.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
use function substr;

class IpV6Strategy extends AClassificationStrategy {
/** @psalm-pure */
#[\Override]
public static function getTypeName(): string {
return 'ipv6';
Expand All @@ -37,9 +38,10 @@
return $loginAddressMapper->findHistoricAndRecentIpv6($validationThreshold, $maxAge);
}

/** @psalm-pure */
#[\Override]
protected function ipToVec(string $ip): array {
$strippedIp = IPv6AddressParser::stripScopeIdentifier($ip);

Check failure on line 44 in lib/Service/IpV6Strategy.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

ImpureMethodCall

lib/Service/IpV6Strategy.php:44:17: ImpureMethodCall: The context is pure but method is impure (see https://psalm.dev/203)
$addr = inet_pton($strippedIp);
if ($addr === false) {
throw new InvalidArgumentException('Invalid IPv6 address');
Expand All @@ -61,13 +63,15 @@
return implode(':', array_map(fn (int $index) => base_convert((string)random_int(0, 2 ** 16 - 1), 10, 16), range(0, 7)));
}

/** @psalm-pure */
#[\Override]
public function getSize(): int {
return 16 + 64;
}

/** @psalm-mutation-free */
#[\Override]
public function getDefaultMlpConfig(): Config {

Check failure on line 74 in lib/Service/IpV6Strategy.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

MissingPureAnnotation

lib/Service/IpV6Strategy.php:74:18: MissingPureAnnotation: getDefaultMlpConfig must be marked @psalm-pure to aid security analysis, run with --alter --issues=MissingPureAnnotation to fix this (see https://psalm.dev/363)
return Config::default()->setEpochs(20);
}
}
3 changes: 3 additions & 0 deletions lib/Service/Ipv4Strategy.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use function explode;

class Ipv4Strategy extends AClassificationStrategy {
/** @psalm-pure */
#[\Override]
public static function getTypeName(): string {
return 'ipv4';
Expand Down Expand Up @@ -47,13 +48,15 @@
return implode('.', array_map(fn (int $index) => random_int(0, 255), range(0, 3)));
}

/** @psalm-pure */
#[\Override]
public function getSize(): int {
return 16 + 32;
}

/** @psalm-mutation-free */
#[\Override]
public function getDefaultMlpConfig(): Config {

Check failure on line 59 in lib/Service/Ipv4Strategy.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

MissingPureAnnotation

lib/Service/Ipv4Strategy.php:59:18: MissingPureAnnotation: getDefaultMlpConfig must be marked @psalm-pure to aid security analysis, run with --alter --issues=MissingPureAnnotation to fix this (see https://psalm.dev/363)
return Config::default();
}
}
1 change: 1 addition & 0 deletions lib/Service/LoginClassifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

class LoginClassifier {

/** @psalm-mutation-free */
public function __construct(
private readonly EstimatorService $estimator,
private readonly IRequest $request,
Expand Down
1 change: 1 addition & 0 deletions lib/Service/LoginDataCollector.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

class LoginDataCollector {

/** @psalm-mutation-free */
public function __construct(
private readonly LoginAddressMapper $addressMapper,
) {
Expand Down
1 change: 1 addition & 0 deletions lib/Service/MLP/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public function __construct(
) {
}

/** @psalm-pure */
public static function default() {
return new static(
330,
Expand Down
2 changes: 2 additions & 0 deletions lib/Service/MLP/OptimizerService.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,14 @@ class OptimizerService {
'learningRate' => [0.0001, 0.01],
];

/** @psalm-mutation-free */
public function __construct(
private readonly DataLoader $loader,
private readonly Trainer $trainer,
) {
}

/** @psalm-mutation-free */
private function printConfig(int $epoch,
float $stepWidth,
Config $config,
Expand Down
1 change: 1 addition & 0 deletions lib/Service/MLP/Trainer.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class Trainer {
/** @var ITimeFactory */
private $timeFactory;

/** @psalm-mutation-free */
public function __construct(ITimeFactory $timeFactory) {
$this->timeFactory = $timeFactory;
}
Expand Down
2 changes: 2 additions & 0 deletions lib/Service/ModelStore.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
class ModelStore {
public const APPDATA_MODELS_FOLDER = 'models';

/** @psalm-mutation-free */
public function __construct(
private readonly ModelMapper $modelMapper,
private readonly IAppData $appData,
Expand All @@ -59,6 +60,7 @@ public function loadLatest(AClassificationStrategy $strategy): Estimator {
return $this->load($latestModel->getId());
}

/** @psalm-pure */
private function getCacheKey(int $id): string {
return "suspicious_login_model_$id";
}
Expand Down
1 change: 1 addition & 0 deletions lib/Service/NotificationState.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/
namespace OCA\SuspiciousLogin\Service;

/** @psalm-immutable */
class NotificationState {
public const SENT = 1;
public const NOT_SENT_DUPLICATE = 2;
Expand Down
2 changes: 2 additions & 0 deletions lib/Service/Statistics/AppStatistics.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

class AppStatistics implements JsonSerializable {

/** @psalm-mutation-free */
public function __construct(
private readonly bool $active,
/** @var Model[] */
Expand Down Expand Up @@ -58,6 +59,7 @@ public function getTrainingDataStatistics(): TrainingDataStatistics {
return $this->trainingDataStatistics;
}

/** @psalm-mutation-free */
#[\Override]
#[ReturnTypeWillChange]
public function jsonSerialize(): array {
Expand Down
2 changes: 2 additions & 0 deletions lib/Service/Statistics/TrainingDataStatistics.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

class TrainingDataStatistics implements JsonSerializable {

/** @psalm-mutation-free */
public function __construct(
private readonly int $loginsCaptured,
private readonly int $loginsAggregated,
Expand All @@ -34,6 +35,7 @@ public function getLoginsAggregated(): int {
return $this->loginsAggregated;
}

/** @psalm-mutation-free */
#[\Override]
#[ReturnTypeWillChange]
public function jsonSerialize(): array {
Expand Down
1 change: 1 addition & 0 deletions lib/Service/StatisticsService.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

class StatisticsService {

/** @psalm-mutation-free */
public function __construct(
private readonly LoginAddressMapper $loginAddressMapper,
private readonly LoginAddressAggregatedMapper $loginAddressAggregatedMapper,
Expand Down
1 change: 1 addition & 0 deletions lib/Service/TrainService.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

class TrainService {

/** @psalm-mutation-free */
public function __construct(
private readonly DataLoader $dataLoader,
private readonly Trainer $trainer,
Expand Down
2 changes: 2 additions & 0 deletions lib/Service/TrainingDataConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

class TrainingDataConfig implements JsonSerializable {

/** @psalm-mutation-free */
public function __construct(
private int $maxAge,
private int $threshold,
Expand Down Expand Up @@ -80,6 +81,7 @@ public function setNow(int $now): TrainingDataConfig {
return $clone;
}

/** @psalm-mutation-free */
#[\Override]
#[ReturnTypeWillChange]
public function jsonSerialize(): array {
Expand Down
Loading
Loading