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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
vendor
/vendor
/.*
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,23 +49,25 @@ Then, add rules:

* `match($regex, $description)`: Checks if the password matches the regex.

* `notInBlacklist($path, $isCaseSensitive = true, $description = null)`: Checks if the password exists in a blacklist.

### Supported Constraints:

The policy also has short-cut helpers for creating constraints:

* `atLeast($n)`: At least the param matches

Equivilant to `between($n, PHP_INT_MAX)`
Equivalent to `between($n, PHP_INT_MAX)`

* `atMost($n)`: At most the param matches

Equivilant to `between(0, $n)`
Equivalent to `between(0, $n)`

* `between($min, $max)`: Between $min and $max number of matches

* `never()`: No matches

Equivilant to `between(0, 0)`
Equivalent to `between(0, 0)`

## Testing the policy

Expand Down
9 changes: 9 additions & 0 deletions lib/PasswordPolicy/Policy.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

class Policy {

/**
* @var Rule[]
*/
protected $rules = array();

public function atLeast($n) {
Expand Down Expand Up @@ -81,6 +84,12 @@ public function match($regex, $description) {
return $this;
}

public function notInBlacklist($path, $isCaseSensitive = true, $description = null) {
$rule = new Rules\Blacklist($path, $isCaseSensitive, $description);
$this->rules[] = $rule;
return $this;
}

public function addRule(Rule $rule) {
$this->rules[] = $rule;
}
Expand Down
3 changes: 3 additions & 0 deletions lib/PasswordPolicy/Rules/Base.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

abstract class Base implements \PasswordPolicy\Rule {

/**
* @var \PasswordPolicy\Constraint
*/
protected $constraint = null;

public function getMessage() {
Expand Down
50 changes: 50 additions & 0 deletions lib/PasswordPolicy/Rules/Blacklist.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

namespace PasswordPolicy\Rules;

class Blacklist {

protected $path;
protected $description;
protected $isCaseSensitive;

/**
* @param string $path File path of blacklist, containing a newline-separated list of passwords
* @param bool $isCaseSensitive Should the blacklist matching be case sensitive?
* @param string $description
*/
public function __construct($path, $isCaseSensitive = true, $description = null) {
if (null === $description) {
$description = 'Expecting a password not in the list "' . basename($path) . '"';
}
$this->path = $path;
$this->isCaseSensitive = (bool) $isCaseSensitive;
$this->description = $description;
}

public function getMessage() {
return $this->description;
}

public function setConstraint(\PasswordPolicy\Constraint $constraint) {
// unused
}

public function test($password) {
$options = "-m 1"; // stop at first match
if (!$this->isCaseSensitive) {
$options .= " -i";
}
$command = "fgrep $options " . escapeshellarg($password) . " " . escapeshellarg($this->path);
$result = shell_exec($command);
return (trim($result) === '');
}

public function toJavaScript() {
return '{
message: "Blacklists not implemented client-side",
check: function(p) { return true; }
}';
}

}