rpcauth.py raw

   1  #!/usr/bin/env python3
   2  # Copyright (c) 2015-2021 The Limenka developers
   3  # Distributed under the MIT software license, see the accompanying
   4  # file COPYING or http://www.opensource.org/licenses/mit-license.php.
   5  
   6  from argparse import ArgumentParser
   7  from getpass import getpass
   8  from secrets import token_hex, token_urlsafe
   9  import hmac
  10  import json
  11  
  12  def generate_salt(size):
  13      """Create size byte hex salt"""
  14      return token_hex(size)
  15  
  16  def generate_password():
  17      """Create 32 byte b64 password"""
  18      return token_urlsafe(32)
  19  
  20  def password_to_hmac(salt, password):
  21      m = hmac.new(salt.encode('utf-8'), password.encode('utf-8'), 'SHA256')
  22      return m.hexdigest()
  23  
  24  def main():
  25      parser = ArgumentParser(description='Create login credentials for a JSON-RPC user')
  26      parser.add_argument('username', help='the username for authentication')
  27      parser.add_argument('password', help='leave empty to generate a random password or specify "-" to prompt for password', nargs='?')
  28      parser.add_argument("-j", "--json", help="output to json instead of plain-text", action='store_true')
  29      parser.add_argument('--output', dest='output', help='file to store credentials, to be used with -rpcauthfile')
  30      args = parser.parse_args()
  31  
  32      if not args.password:
  33          args.password = generate_password()
  34      elif args.password == '-':
  35          args.password = getpass()
  36  
  37      # Create 16 byte hex salt
  38      salt = generate_salt(16)
  39      password_hmac = password_to_hmac(salt, args.password)
  40      rpcauth = f'{args.username}:{salt}${password_hmac}'
  41  
  42      if args.output:
  43          file = open(args.output, "a", encoding="utf8")
  44          file.write(rpcauth + "\n")
  45  
  46      if args.json:
  47          odict={'username':args.username, 'password':args.password}
  48          if not args.output:
  49              odict['rpcauth'] = rpcauth
  50          print(json.dumps(odict))
  51      else:
  52          if not args.output:
  53              print('String to be appended to limenka.conf:')
  54              print(f'rpcauth={rpcauth}')
  55          print(f'Your password:\n{args.password}')
  56  
  57  if __name__ == '__main__':
  58      main()
  59