#!/usr/bin/env python3
# details on rabbitMQ password hashing
# https://www.rabbitmq.com/passwords.html#computing-password-hash

from __future__ import print_function
import base64
import os
import hashlib
import struct
import getpass
import argparse
import sys
import json

rabbitmq_config_file = '/etc/rabbitmq/definitions.json'
parser = argparse.ArgumentParser(
                    prog = 'rabbitmq_password2hash',
                    description = 'This script will generate hash from string (password) which can be used in RabbitMQ configuration')

parser.add_argument('-u', '--user', help="RabbitMQ user name")
parser.add_argument('-p', '--password', help="string which should be hashed")
parser.add_argument('-d', '--delete', help="delete user from " + rabbitmq_config_file + " (-u and -w should be set)", action='store_true')
parser.add_argument('-w', '--write', help="save changes to " + rabbitmq_config_file, action='store_true')
args = parser.parse_args()

if args.delete:
# Если хотим удалить пользователя, то нужен логин
  min_argv = 4
elif args.write:
# Если хотим создать пользователя и писать изменения в файл, то нужен и логин, и пароль
  min_argv = 6
else:
# печать пароля на stdout
  min_argv = 3

if len(sys.argv) < min_argv:
  parser.print_help()
  print("\n\nInteractive mode. Enter credentials or press Ctrl+С to exit.")
# Ask user name when we want update config file
  if args.write:
    print("Username and password will be written to " + rabbitmq_config_file)

  if args.delete or args.write:
    username1 = args.user
    if username1 is None:
      username1 = input("Enter user name: ")

# This is the password we wish to encode
  password1 = args.password
  password2 = args.password
  if password1 is None and not args.delete:
    password1 = getpass.getpass("Enter password: ")
    password2 = getpass.getpass("Enter password again: ")

  if password1 != password2:
    print("Error: passwords do not match")
    exit(1)
else:
  username1 = args.user
  if username1 is None and args.write:
    print("Error: user name was not set")
    exit(2)
  password1 = args.password
  if password1 is None and not args.delete:
    print("Error: password was not set")
    exit(3)


# 1.Generate a random 32 bit salt:
# This will generate 32 bits of random data:
salt = os.urandom(4)

# 2.Concatenate that with the UTF-8 representation of the password
if not args.delete:
  tmp0 = salt + password1.encode('utf-8')
  # 3. Take the SHA256 hash and get the bytes back
  tmp1 = hashlib.sha256(tmp0).digest()
  # 4. Concatenate the salt again:
  salted_hash = salt + tmp1
  # 5. convert to base64 encoding:
  pass_hash = base64.b64encode(salted_hash)
  # 6. print hash
  if not args.write:
    print(pass_hash.decode('utf-8'))
    exit(0)

# 7. write changes (add/modify/delete user) to file if -w arg was set
with open(rabbitmq_config_file, "r") as json_file:
  json_data = json.load(json_file)
  json_file.close()
#print(json_data)
#print("\n\n\n")
user_exist = False
for attribute_lev1 in json_data:
#  print("attribute_lev1: " + attribute_lev1)
  if attribute_lev1 == "users":
    for json_users in json_data["users"]:
      if json_users["name"] == username1:
        if args.delete:
          json_data["users"].remove(json_users);
        else:
#          print("json_user: " + json.dumps(json_users))
          json_users["password_hash"] = pass_hash.decode('utf-8')
          user_exist = True
    break

if not user_exist and not args.delete:
  new_user_data = '{"name": "' + username1 + '", "password_hash": "' + pass_hash.decode('utf-8') + '", "hashing_algorithm": "rabbit_password_hashing_sha256", "tags": "" }'
  new_user_json = json.loads(new_user_data)
  json_data["users"].append(new_user_json)

#print(json_data)
with open(rabbitmq_config_file, "w") as json_file:
  json_file.write(json.dumps(json_data, indent=4, sort_keys=False))
  json_file.close()
  print("New settings was saved to " + rabbitmq_config_file)
