passExtensions.pass-audit: 0.1 -> 1.0.1, refactor

Updates to v1.0.1[1] which supports subdirs and zxcvbn[2]-based
complexity checks. Also, the following things changed:

* Add separate output for man-pages
* Enable test-suite (after adding a patch which mocks the
  `pwnedpasswords.com`).
* Added myself as maintainer.

[1] https://github.com/roddhjav/pass-audit/releases/tag/v1.0.1 /
    https://github.com/roddhjav/pass-audit/releases/tag/v1.0

[2] https://pypi.org/project/zxcvbn-python/
This commit is contained in:
Maximilian Bosch 2020-03-15 20:15:07 +01:00
parent 5eb01e1a7f
commit 16001eab7c
No known key found for this signature in database
GPG key ID: 091DBF4D1FC46B8E
5 changed files with 255 additions and 43 deletions

View file

@ -1,42 +0,0 @@
{ stdenv, pass, fetchFromGitHub, pythonPackages, makeWrapper }:
let
pythonEnv = pythonPackages.python.withPackages (p: [ p.requests ]);
in stdenv.mkDerivation rec {
pname = "pass-audit";
version = "0.1";
src = fetchFromGitHub {
owner = "roddhjav";
repo = "pass-audit";
rev = "v${version}";
sha256 = "0v0db8bzpcaa7zqz17syn3c78mgvw4mpg8qg1gh5rmbjsjfxw6sm";
};
nativeBuildInputs = [ makeWrapper ];
buildInputs = [ pythonEnv ];
patchPhase = ''
sed -i -e "s|/usr/lib|$out/lib|" audit.bash
sed -i -e 's|$0|${pass}/bin/pass|' audit.bash
'';
dontBuild = true;
installFlags = [ "PREFIX=$(out)" ];
postFixup = ''
wrapProgram $out/lib/password-store/extensions/audit.bash \
--prefix PATH : "${pythonEnv}/bin" \
--run "export PREFIX"
'';
meta = with stdenv.lib; {
description = "Pass extension for auditing your password repository.";
homepage = https://github.com/roddhjav/pass-audit;
license = licenses.gpl3Plus;
platforms = platforms.unix;
};
}

View file

@ -0,0 +1,175 @@
From 37c2b4d2940476555aeec20fe1e5e3fa0492a94e Mon Sep 17 00:00:00 2001
From: Maximilian Bosch <maximilian@mbosch.me>
Date: Sun, 15 Mar 2020 19:58:53 +0100
Subject: [PATCH] Make it possible to run the tests offline
Helpful when developing without network access, also makes sure that
the test actually depend on the API's data like number of breaches
(which will change in time).
---
tests/commons.py | 25 +++++++++++++++++++++++++
tests/test_audit.py | 8 +++++---
tests/test_pass_audit.py | 10 +++++++++-
tests/test_pwned.py | 8 +++++---
4 files changed, 44 insertions(+), 7 deletions(-)
diff --git a/tests/commons.py b/tests/commons.py
index 13c4cb1..4f1ecd8 100644
--- a/tests/commons.py
+++ b/tests/commons.py
@@ -56,3 +56,28 @@ class TestPass(TestBase):
for path in self.store.list(root):
data[path] = self.store.show(path)
return data
+
+
+def mock_request(*args, **kwargs):
+ class MockResponse:
+ def __init__(self):
+ data = [
+ "D5EE0CB1A41071812CCED2F1930E6E1A5D2:2",
+ "2DC183F740EE76F27B78EB39C8AD972A757:52579",
+ "CF164D7A51A1FD864B1BF9E1CE8A3EC171B:4",
+ "D0B910E7A3028703C0B30039795E908CEB2:7",
+ "AD6438836DBE526AA231ABDE2D0EEF74D42:3",
+ "EBAB0A7CE978E0194608B572E4F9404AA21:3",
+ "17727EAB0E800E62A776C76381DEFBC4145:120",
+ "5370372AC65308F03F6ED75EC6068C8E1BE:1386",
+ "1E4C9B93F3F0682250B6CF8331B7EE68FD8:3730471",
+ "437FAA5A7FCE15D1DDCB9EAEAEA377667B8:123422",
+ "944C22589AC652B0F47918D58CA0CDCCB63:411"
+ ]
+
+ self.text = "\r\n".join(data)
+
+ def raise_for_status(self):
+ pass
+
+ return MockResponse()
diff --git a/tests/test_audit.py b/tests/test_audit.py
index d8c7a9a..5e0a9cf 100644
--- a/tests/test_audit.py
+++ b/tests/test_audit.py
@@ -17,12 +17,13 @@
#
from .. import pass_audit
-from tests.commons import TestPass
-
+from tests.commons import TestPass, mock_request
+from unittest import mock
class TestPassAudit(TestPass):
passwords_nb = 7
+ @mock.patch('requests.get', mock_request)
def test_password_notpwned(self):
"""Testing: pass audit for password not breached with K-anonymity method."""
data = self._getdata("Password/notpwned")
@@ -30,9 +31,10 @@ class TestPassAudit(TestPass):
breached = audit.password()
self.assertTrue(len(breached) == 0)
+ @mock.patch('requests.get', mock_request)
def test_password_pwned(self):
"""Testing: pass audit for password breached with K-anonymity method."""
- ref_counts = [51259, 3, 114, 1352, 3645804, 78773, 396]
+ ref_counts = [52579, 3, 120, 1386, 3730471, 123422, 411]
data = self._getdata("Password/pwned")
audit = pass_audit.PassAudit(data)
breached = audit.password()
diff --git a/tests/test_pass_audit.py b/tests/test_pass_audit.py
index 4c10f87..2c949f7 100644
--- a/tests/test_pass_audit.py
+++ b/tests/test_pass_audit.py
@@ -19,7 +19,8 @@
import os
from .. import pass_audit
-from tests.commons import TestPass
+from tests.commons import TestPass, mock_request
+from unittest import mock
class TestPassAuditCMD(TestPass):
@@ -47,6 +48,7 @@ class TestPassAuditCMD(TestPass):
cmd = ['--not-an-option', '-q']
self._passaudit(cmd, 2)
+ @mock.patch('requests.get', mock_request)
def test_pass_audit_StoreNotInitialized(self):
"""Testing: store not initialized."""
cmd = ['Password/', '-v']
@@ -56,6 +58,7 @@ class TestPassAuditCMD(TestPass):
os.rename(os.path.join(self.store.prefix, 'backup.gpg-id'),
os.path.join(self.store.prefix, '.gpg-id'))
+ @mock.patch('requests.get', mock_request)
def test_pass_audit_InvalidID(self):
"""Testing: invalid user ID."""
os.rename(os.path.join(self.store.prefix, '.gpg-id'),
@@ -66,26 +69,31 @@ class TestPassAuditCMD(TestPass):
os.rename(os.path.join(self.store.prefix, 'backup.gpg-id'),
os.path.join(self.store.prefix, '.gpg-id'))
+ @mock.patch('requests.get', mock_request)
def test_pass_audit_NotAFile(self):
"""Testing: pass audit not_a_file."""
cmd = ['not_a_file']
self._passaudit(cmd, 1)
+ @mock.patch('requests.get', mock_request)
def test_pass_audit_passwords_notpwned(self):
"""Testing: pass audit Password/notpwned."""
cmd = ['Password/notpwned']
self._passaudit(cmd)
+ @mock.patch('requests.get', mock_request)
def test_pass_audit_passwords_pwned(self):
"""Testing: pass audit Password/pwned."""
cmd = ['Password/pwned']
self._passaudit(cmd)
+ @mock.patch('requests.get', mock_request)
def test_pass_audit_passwords_good(self):
"""Testing: pass audit Password/good."""
cmd = ['Password/good']
self._passaudit(cmd)
+ @mock.patch('requests.get', mock_request)
def test_pass_audit_passwords_all(self):
"""Testing: pass audit ."""
cmd = ['']
diff --git a/tests/test_pwned.py b/tests/test_pwned.py
index 5ce6bc6..c28939a 100644
--- a/tests/test_pwned.py
+++ b/tests/test_pwned.py
@@ -17,7 +17,8 @@
#
from .. import pass_audit
-from tests.commons import TestPass
+from tests.commons import TestPass, mock_request
+from unittest import mock
class TestPwnedAPI(TestPass):
@@ -25,12 +26,13 @@ class TestPwnedAPI(TestPass):
def setUp(self):
self.api = pass_audit.PwnedAPI()
+ @mock.patch('requests.get', mock_request)
def test_password_range(self):
"""Testing: https://api.haveibeenpwned.com/range API."""
prefix = '21BD1'
Hash = '21BD12DC183F740EE76F27B78EB39C8AD972A757'
hashes, counts = self.api.password_range(prefix)
self.assertIn(Hash, hashes)
- self.assertTrue(counts[hashes.index(Hash)] == 51259)
+ self.assertTrue(counts[hashes.index(Hash)] == 52579)
self.assertTrue(len(hashes) == len(counts))
- self.assertTrue(len(hashes) == 527)
+ self.assertTrue(len(hashes) == 11)
--
2.25.0

View file

@ -0,0 +1,28 @@
From 8f76b32946430737f97f2702afd828b09536afd2 Mon Sep 17 00:00:00 2001
From: Maximilian Bosch <maximilian@mbosch.me>
Date: Sun, 15 Mar 2020 20:10:11 +0100
Subject: [PATCH 2/2] Fix audit.bash setup
This sets PASSWORD_STORE_DIR (needed by the python-code) to
PASSWORD_STORE_DIR and properly falls back to `~/.password-store` if
it's not set.
---
audit.bash | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/audit.bash b/audit.bash
index 7a973dc..c40ff76 100755
--- a/audit.bash
+++ b/audit.bash
@@ -17,7 +17,7 @@
#
cmd_audit() {
- export PASSWORD_STORE_DIR=$PREFIX GIT_DIR PASSWORD_STORE_GPG_OPTS
+ export PASSWORD_STORE_DIR=${PASSWORD_STORE_DIR:-$HOME/.password-store} GIT_DIR PASSWORD_STORE_GPG_OPTS
export X_SELECTION CLIP_TIME PASSWORD_STORE_UMASK GENERATED_LENGTH
export CHARACTER_SET CHARACTER_SET_NO_SYMBOLS EXTENSIONS PASSWORD_STORE_KEY
export PASSWORD_STORE_ENABLE_EXTENSIONS PASSWORD_STORE_SIGNING_KEY
--
2.25.0

View file

@ -0,0 +1,51 @@
{ stdenv, pass, fetchFromGitHub, pythonPackages, makeWrapper, gnupg }:
let
pythonEnv = pythonPackages.python.withPackages (p: [ p.requests p.setuptools p.zxcvbn ]);
in stdenv.mkDerivation rec {
pname = "pass-audit";
version = "1.0.1";
src = fetchFromGitHub {
owner = "roddhjav";
repo = "pass-audit";
rev = "v${version}";
sha256 = "1mdckw0dwcnv8smp1za96y0zmdnykbkw2606v7mzfnzbz4zjdlwl";
};
patches = [
./0001-Make-it-possible-to-run-the-tests-offline.patch
./0002-Fix-audit.bash-setup.patch
];
postPatch = ''
substituteInPlace audit.bash \
--replace '/usr/bin/env python3' "${pythonEnv}/bin/python3"
'';
outputs = [ "out" "man" ];
buildInputs = [ pythonEnv ];
nativeBuildInputs = [ makeWrapper ];
doCheck = true;
checkInputs = [ pythonPackages.green pass gnupg ];
checkPhase = ''
${pythonEnv}/bin/python3 setup.py green -q
'';
installFlags = [ "DESTDIR=${placeholder "out"}" "PREFIX=" ];
postInstall = ''
wrapProgram $out/lib/password-store/extensions/audit.bash \
--prefix PYTHONPATH : "$out/lib/${pythonEnv.libPrefix}/site-packages"
'';
meta = with stdenv.lib; {
description = "Pass extension for auditing your password repository.";
homepage = https://github.com/roddhjav/pass-audit;
license = licenses.gpl3Plus;
platforms = platforms.unix;
maintainers = with maintainers; [ ma27 ];
};
}

View file

@ -3,7 +3,7 @@
with pkgs;
{
pass-audit = callPackage ./audit.nix {
pass-audit = callPackage ./audit {
pythonPackages = python3Packages;
};
pass-checkup = callPackage ./checkup.nix {};