Mercurial > p > roundup > code
comparison roundup/admin.py @ 7209:c1227f883177
Implement password hash testing using new roundup-admin perftest.
Add new anypy/time_.py to provide a suitable definition for
perf_counter for python2 or 3.
Also update examples in upgrading.txt, man page, new translatable
strings in locale.
| author | John Rouillard <rouilj@ieee.org> |
|---|---|
| date | Fri, 03 Mar 2023 17:37:44 -0500 |
| parents | 65b12a9dd11c |
| children | 07ce4e4110f5 |
comparison
equal
deleted
inserted
replaced
| 7208:c9fa0ffb0f94 | 7209:c1227f883177 |
|---|---|
| 1745 else: | 1745 else: |
| 1746 print(_('No migration action required. At schema version %s.') % | 1746 print(_('No migration action required. At schema version %s.') % |
| 1747 self.db.database_schema['version']) | 1747 self.db.database_schema['version']) |
| 1748 return 0 | 1748 return 0 |
| 1749 | 1749 |
| 1750 def do_perftest(self, args): | |
| 1751 ''"""Usage: perftest [mode] [arguments]* | |
| 1752 | |
| 1753 Time operations in Roundup. Supported arguments: | |
| 1754 | |
| 1755 [password] [rounds=<integer>] [scheme=<scheme>] | |
| 1756 | |
| 1757 'password' is the default mode. The tracker's config.ini | |
| 1758 setting for 'password_pbkdf2_default_rounds' is the default | |
| 1759 value for 'rounds'. On the command line, 'rounds' can include | |
| 1760 thousands separator of ',' or '.'. 'scheme' is the default | |
| 1761 coded into Roundup. List supported schemes by using 'scheme='. | |
| 1762 | |
| 1763 """ | |
| 1764 from roundup.anypy.time_ import perf_counter | |
| 1765 | |
| 1766 props = { "rounds": self.db.config.PASSWORD_PBKDF2_DEFAULT_ROUNDS, | |
| 1767 "scheme": password.Password.known_schemes[0] | |
| 1768 } | |
| 1769 | |
| 1770 print_supported_schemes = lambda: print( | |
| 1771 "Supported schemes (default is first, case " | |
| 1772 "sensitive):\n %s." % | |
| 1773 ", ".join(password.Password.known_schemes)) | |
| 1774 | |
| 1775 if (args[0].find("=") != -1): | |
| 1776 args.insert(0, 'password') | |
| 1777 | |
| 1778 props.update(self.props_from_args(args[1:])) | |
| 1779 | |
| 1780 if args[0] == "password": | |
| 1781 try: | |
| 1782 # convert 10,000,000 or 10.000.000 to 10000000 | |
| 1783 r = int(re.sub('[,.]','',props['rounds'])) | |
| 1784 if r < 1000: | |
| 1785 print(_("Invalid 'rounds'. Must be larger than 999.")) | |
| 1786 return | |
| 1787 props['rounds'] = r | |
| 1788 except (TypeError, ValueError): | |
| 1789 print(_("Invalid 'rounds'. It must be an integer not: %s") % | |
| 1790 props['rounds']) | |
| 1791 return | |
| 1792 if props['scheme'] == None: | |
| 1793 print_supported_schemes() | |
| 1794 return | |
| 1795 | |
| 1796 self.db.config.PASSWORD_PBKDF2_DEFAULT_ROUNDS = props['rounds'] | |
| 1797 | |
| 1798 try: | |
| 1799 tic = perf_counter() | |
| 1800 pw_hash = password.encodePassword( | |
| 1801 "this is a long password to hash", | |
| 1802 props['scheme'], | |
| 1803 None, | |
| 1804 config=self.db.config | |
| 1805 ) | |
| 1806 toc = perf_counter() | |
| 1807 except password.PasswordValueError as e: | |
| 1808 print(e) | |
| 1809 print_supported_schemes() | |
| 1810 return | |
| 1811 | |
| 1812 if props['scheme'].startswith('PBKDF2'): | |
| 1813 (rounds, salt, _raw_salt, digest) = password.pbkdf2_unpack( | |
| 1814 pw_hash) | |
| 1815 else: | |
| 1816 rounds = _("scheme does not support rounds.") | |
| 1817 | |
| 1818 print(_( | |
| 1819 "Hash time: %(time)0.9f seconds, scheme: %(scheme)s, " | |
| 1820 "rounds: %(rounds)s") % | |
| 1821 { "time": toc-tic, "scheme": props['scheme'], | |
| 1822 "rounds": rounds}) | |
| 1823 | |
| 1750 def run_command(self, args): | 1824 def run_command(self, args): |
| 1751 """Run a single command | 1825 """Run a single command |
| 1752 """ | 1826 """ |
| 1753 command = args[0] | 1827 command = args[0] |
| 1754 | 1828 |
