Skip to content

Commit

Permalink
Merge pull request #11 from backpacker69/master
Browse files Browse the repository at this point in the history
using gpg to encrypt and decrypt keystore
  • Loading branch information
peerchemist authored May 26, 2017
2 parents 2d570d6 + 949c11a commit b841281
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 16 deletions.
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

0 comments on commit b841281

Please sign in to comment.