A web server for doing quick budgeting
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

125 lines
3.9 KiB

  1. #!/usr/bin/env python
  2. #
  3. # Password manager: handles hashing and comparing for passwords used.
  4. # I'm no expert so use and trust at your own risk!
  5. #
  6. from passlib.context import CryptContext
  7. # It's not strictly necessary to import these, but I do it here for PyInstaller
  8. # (see https://github.com/pyinstaller/pyinstaller/issues/649)
  9. import argon2
  10. import cffi
  11. import configparser
  12. import passlib.handlers
  13. import passlib.handlers.argon2
  14. import passlib.handlers.sha2_crypt
  15. import passlib.handlers.bcrypt
  16. import sys
  17. import os
  18. import json
  19. import getpass
  20. # Even if this file gets compromised, it'll still be hard to use for anything due to salting
  21. accountsFilename = "accounts.json"
  22. password_context = CryptContext(
  23. # Replace this list with the hash(es) you wish to support.
  24. # this example sets pbkdf2_sha256 as the default,
  25. # with additional support for reading legacy des_crypt hashes.
  26. schemes=["argon2", "sha512_crypt", "bcrypt"],
  27. # Automatically mark all but first hasher in list as deprecated.
  28. # (this will be the default in Passlib 2.0)
  29. deprecated="auto",
  30. # Optionally, set the number of rounds that should be used.
  31. # Appropriate values may vary for different schemes,
  32. # and the amount of time you wish it to take.
  33. # Leaving this alone is usually safe, and will use passlib's defaults.
  34. ## pbkdf2_sha256__rounds = 29000,
  35. )
  36. accounts = {}
  37. # Note that this class needs to be kept simple, otherwise JSON serialization will break
  38. class Account:
  39. def __init__(self, username, passwordHashed):
  40. self.username = username
  41. self.passwordHashed = passwordHashed
  42. def havePasswordsBeenSet():
  43. return os.path.exists(accountsFilename)
  44. def loadAccounts():
  45. global accounts
  46. if not havePasswordsBeenSet():
  47. return
  48. passwordsFile = open(accountsFilename, "r")
  49. accountsJson = passwordsFile.readlines()
  50. passwordsFile.close()
  51. for line in accountsJson:
  52. accountParsed = json.loads(line)
  53. account = Account(accountParsed["username"], accountParsed["passwordHashed"])
  54. accounts[account.username] = account
  55. def verify(username, password):
  56. if not accounts:
  57. loadAccounts()
  58. if not accounts:
  59. raise Exception("Tried to verify an account, but {} has no accounts or does not exist!"
  60. .format(accountsFilename))
  61. if username not in accounts:
  62. # Username not found
  63. return False
  64. else:
  65. if password_context.verify(password, accounts[username].passwordHashed):
  66. return True
  67. return False
  68. def createAccount(username, password):
  69. if not accounts:
  70. loadAccounts()
  71. if username in accounts:
  72. return (False, "Failed to create account: Username not unique")
  73. passwordHashed = password_context.hash(password)
  74. accountPair = Account(username, passwordHashed)
  75. accountsOutFile = open(accountsFilename, "a")
  76. json.dump(accountPair.__dict__, accountsOutFile)
  77. accountsOutFile.write("\n")
  78. accountsOutFile.close()
  79. loadAccounts()
  80. return (True, "Account created successfully")
  81. if __name__ == "__main__":
  82. print("PasswordManager: Create a new account\n")
  83. username = input("\tEnter username: ")
  84. password = None
  85. while True:
  86. password = getpass.getpass("\tEnter password: ")
  87. verifyPassword = getpass.getpass("\tVerify password: ")
  88. if not password:
  89. print("Please enter a password")
  90. elif password != verifyPassword:
  91. print("Passwords do not match! Try again")
  92. else:
  93. break
  94. result = createAccount(username, password)
  95. print("[Create Account] {}".format(result[1]))
  96. if result[0]:
  97. # To verify
  98. print("Account created! Please test.")
  99. username = input("\tEnter username: ")
  100. password = getpass.getpass("\tEnter password: ")
  101. print("Authentication successful: {}".format(verify(username, password)))