Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

using gpg to encrypt and decrypt keystore #11

Merged
merged 3 commits into from
May 26, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 27 additions & 5 deletions pacli/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,23 @@
import json
import logging

from pacli.keystore import read_keystore, write_keystore, KeyedProvider

conf_dir = user_config_dir("pacli")
conf_file = os.path.join(conf_dir, "pacli.conf")
logfile = os.path.join(conf_dir, "pacli.log")
keyfile = os.path.join(conf_dir, "pacli.gpg")

class Settings:
pass

def load_conf():
'''load user configuration'''

user_config = read_conf(conf_file)
for key in user_config:
setattr(Settings, key, user_config[key])
settings = read_conf(conf_file)

for key in settings:
setattr(Settings, key, settings[key])

logging.basicConfig(filename=logfile, level=logging.getLevelName(Settings.loglevel))
logging.basicConfig(level=logging.getLevelName(Settings.loglevel),
Expand All @@ -37,6 +41,8 @@ def first_run():
os.mkdir(conf_dir)
if not os.path.exists(conf_file):
write_default_config(conf_file)
if not os.path.exists(keyfile):
open(keyfile, 'a').close()

def set_up(provider):
'''setup'''
Expand All @@ -50,7 +56,8 @@ def set_up(provider):
if not Settings.production:
if not provider.listtransactions("PATEST"):
pa.pautils.load_p2th_privkeys_into_local_node(provider, prod=False)

else:
pa.pautils.load_p2th_privkeys_into_local_node(provider,keyfile)

def default_account_utxo(provider, amount):
'''set default address to be used with pacli'''
Expand Down Expand Up @@ -803,12 +810,25 @@ def cli():
def main():

first_run()
load_conf()

try:
load_conf()
except:
raise

mypg = None
password = None
mykeys = ""
mykeys = read_keystore(Settings,keyfile)

if Settings.provider.lower() == "rpcnode":
provider = pa.RpcNode(testnet=Settings.testnet)
if Settings.provider.lower() == "holy":
provider = pa.Holy(network=Settings.network)

provider = KeyedProvider(provider,keysJson=mykeys)
set_up(provider)

args = cli()

if args.status:
Expand Down Expand Up @@ -858,5 +878,7 @@ def main():
if args.info:
vote_info(provider, args.info)

write_keystore(Settings,keyfile,provider.dumpprivkeys())

if __name__ == "__main__":
main()
33 changes: 23 additions & 10 deletions pacli/config.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,36 @@
import configparser
import sys
from .default_conf import default_conf

def write_default_config(conf_file):
def write_default_config(conf_file=None):
print("writing default config")
config = configparser.ConfigParser()
config["settings"] = default_conf
with open(conf_file, 'w') as configfile:
config.write(configfile)
if not conf_file:
config.write()
else:
with open(conf_file, 'w') as configfile:
config.write(configfile)

def read_conf(conf_file):
config = configparser.ConfigParser()
config.read(conf_file)
settings = {
"network": config["settings"]["network"],
"production": config["settings"]["production"],
"loglevel": config["settings"]["loglevel"],
"change": config["settings"]["change"],
"provider": config["settings"]["provider"]
}
try:
settings = {
"network": config["settings"]["network"],
"production": config["settings"]["production"],
"loglevel": config["settings"]["loglevel"],
"change": config["settings"]["change"],
"provider": config["settings"]["provider"],
"keystore": config["settings"]["keystore"],
"gnupgdir": config["settings"]["gnupgdir"],
"gnupgagent": config["settings"]["gnupgagent"],
"gnupgkey": config["settings"]["gnupgkey"]
}
except:
print("config is outdated, saving current default config to",conf_file+".sample")
write_default_config(conf_file+".sample")
raise

if settings["network"].startswith("t"):
settings["testnet"] = True
Expand Down
6 changes: 5 additions & 1 deletion pacli/default_conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,9 @@
"production": True,
"change": "default",
"provider": "rpcnode",
"loglevel": "WARNING" # WARNING, INFO, DEBUG
"loglevel": "WARNING", # WARNING, INFO, DEBUG
"keystore": "gnupg",
"gnupgdir": "~/.gnupg/",
"gnupgagent": False,
"gnupgkey": "any"
}
77 changes: 77 additions & 0 deletions pacli/keystore.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import gnupg
import getpass
import sys
from pypeerassets.kutil import Kutil

mypg = None

def read_keystore(Settings,keyfile) -> str:
mykeys = ""

if Settings.keystore == "gnupg" and Settings.provider != "rpcnode":
mypg = gnupg.GPG(binary='/usr/bin/gpg',homedir=Settings.gnupgdir,use_agent=bool(Settings.gnupgagent=="True"),keyring='pubring.gpg',secring='secring.gpg')
password = getpass.getpass("Input gpg key password:")
fd = open(keyfile)
data = fd.read()

if len(data)>0:
mykeys = str(mypg.decrypt(data,passphrase=password))
fd.close()
else:
print("using rpcnode")

return mykeys

def write_keystore(Settings,keyfile,keys):

if mypg:
data = str(mypg.encrypt(str(keys),Settings.gnupgkey))
fd = open(keyfile,"w")
fd.write(data)
fd.close()

class KeyedProvider:

"""
Keystore class
"""

@classmethod
def __init__(self, provider, keysJson: str=""):
"""
:
"""
self.provider = provider

if keysJson != "":
self.privkeys = eval(keysJson)
else:
self.privkeys = {}

@classmethod
def __getattr__(self, name):
return getattr(self.provider, name)

@classmethod
def importprivkey(self, privkey: str, label: str) -> int:
"""import <privkey> with <label>"""
mykey = Kutil(wif=privkey)

if label not in self.privkeys.keys():
self.privkeys[label] = []

if mykey._privkey not in [key['privkey'] for key in self.privkeys[label]]:
self.privkeys[label].append({"privkey":mykey._privkey,"address":mykey.address})

@classmethod
def getaddressesbyaccount(self, label: str) -> list:
if label in self.privkeys.keys():
return [key["address"] for key in self.privkeys[label]]

@classmethod
def listaccounts(self) -> dict:
return {key:0 for key in self.privkeys.keys()}

@classmethod
def dumpprivkeys(self) -> dict:
return self.privkeys
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pypeerassets>=0.1.1
terminaltables>=3.1.0
gnupg>=2.1
appdirs