Skip to content

Commit

Permalink
Merge c881f9e into b69685c
Browse files Browse the repository at this point in the history
  • Loading branch information
weex committed Mar 14, 2017
2 parents b69685c + c881f9e commit b46c7c3
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 42 deletions.
12 changes: 6 additions & 6 deletions doc/key-management.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Key Management in python-rein

* Privacy - Keys involved in a transaction only need to be known by parties to that transaction.
This means knowing a key that is used to sign a document or payment should not lead to the
discovery of a user's other keys.
discovery of a user''s other keys.

* Multilayered security - An identity is defined by a 12-word mnemonic seed. The seed is used to
generate a root BIP32 key.
Expand All @@ -17,13 +17,13 @@ to use.

* Root key (m) - Derived from the 12-word mnemonic seed.

* Master signing key (m/0) - This key is used to sign the primary document defining a user's identity
* Master signing key (m/0) - This key is used to sign the primary document defining a user''s identity
in Rein, called an enrollment. In includes name, contact info, whether a user is willing to be a
mediator in others transactions and their desired fee rate. The enrollment also includes a Secure
Identity Number (SIN), generated from the master signing key. This SIN is specified on the Bitcoin
wiki as Identity Protocol v1 and used by Bitrated as a unique identifier for a user.

* Delegate key (m/1'/0) - A delegate key is used for day-to-day signatures of documents like job
* Delegate key (m/1''/0) - A delegate key is used for day-to-day signatures of documents like job
postings, bids, offers, disputes and is also used for controlling payments.

###Deficiencies with current implementation:
Expand All @@ -34,15 +34,15 @@ to use.
job), obviously not desirable when handling money.

* The public part of the key used to sign documents must be made available so that others can verify
their authenticity. Since this same key is used to generate a user's payment address meaning all
their authenticity. Since this same key is used to generate a user''s payment address meaning all
incoming payments and document signatures are trivially linked.

###Future directions:

* Unique public keys per escrow (m/1'/k with k > 0) - A unique key will be generated from the BIP32 tree
* Unique public keys per escrow (m/1''/k with k > 0) - A unique key will be generated from the BIP32 tree
for each post or bid. This key will be used to build escrow addresses and to sign payments at
conclusion of each job.

* Unique internal wallet address per job (m/0'/k) - A unique payment address will be generated from the
* Unique internal wallet address per job (m/0''/k) - A unique payment address will be generated from the
BIP32 tree for each post or bid. This is where funds will be sent when payments are sent from escrow
back to a client, to a mediator, or to a freelancer.
49 changes: 39 additions & 10 deletions rein/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -1202,12 +1202,13 @@ def status(multi, identity, jobid):
else:
click.echo("Job id not found")


def config_common(key, value):
"""
Set configuration variable. Parses true/false, on/off, and passes
anything else unaltered to the db.
"""
keys = ['testnet', 'tor', 'debug', 'fee', 'trust_score']
keys = ['testnet', 'tor', 'debug', 'fee', 'blockexplorer', 'api', 'trust_score']
if key not in keys:
click.echo("Invalid config setting. Try one of " + ', '.join(keys))
return
Expand All @@ -1216,9 +1217,12 @@ def config_common(key, value):
PersistConfig.set(rein, key, 'true')
elif value and value.lower() in ['off', 'false', 'disabled']:
PersistConfig.set(rein, key, 'false')
else:
elif value:
PersistConfig.set(rein, key, value)

click.echo(PersistConfig.get(rein, key))


@cli.command()
@click.argument('key', required=True)
@click.argument('value', required=True)
Expand Down Expand Up @@ -1286,11 +1290,14 @@ def debug(debug):

def init(multi, identity):
log = rein.get_log()

if multi:
rein.set_multiuser()

if rein.has_no_account():
click.echo("Please run setup.")
return sys.exit(1)

user = get_user(rein, identity, True)
key = pubkey(user.dkey)
urls = Bucket.get_urls(rein)
Expand All @@ -1312,12 +1319,14 @@ def is_int(s):
except ValueError:
return False


def is_tags(s):
if re.search(r'[^a-z0-9 ,]', s.lower()):
return False
else:
return True


def get_user(rein, identity, enrolled):
if rein.multi and identity:
rein.user = rein.session.query(User).filter(
Expand Down Expand Up @@ -1542,11 +1551,16 @@ def rate_web():
user_jobs = get_user_jobs(rein)
return render_template("rate.html", form=form, user_sin=user.msin, user=user, user_jobs=user_jobs)

@app.route('/ratings/<msin>', methods=['GET'])
def view_ratings(msin):
@app.route('/profile/<msin>', methods=['GET'])
def view_profile(msin):
display_trust_score = PersistConfig.get(rein, 'trust_score', False)
ratings = get_all_user_ratings(log, url, user, rein, msin)
return render_template("ratings.html", user=user, user_rated=get_user_name(log, url, user, rein, msin), msin=msin, ratings=ratings, display_trust_score=display_trust_score)
return render_template("profile.html",
user=user,
user_rated=get_user_name(log, url, user, rein, msin),
msin=msin,
ratings=ratings,
display_trust_score=display_trust_score)

@app.route('/hide', methods=['POST'])
def hide():
Expand Down Expand Up @@ -1652,8 +1666,11 @@ def job_post():
if m.msin in [hidden_mediator['content_identifier'] for hidden_mediator in hidden_mediator_content]:
continue

mediator_maddrs.append((m.maddr, '{}</td><td>{}%</td><td>{}</td><td><a href="mailto:{}" target="_blank">{}</a></td><td>{}'.\
format(m.username,
mediator_maddrs.append((m.maddr,
'<a href="/profile/{}">{}</a></td><td>{}%</td><td>{}</td>'
'<td><a href="mailto:{}" target="_blank">{}</a></td><td>{}'.\
format(m.msin,
m.username,
m.mediator_fee,
get_average_user_rating_display(log, url, user, rein, m.msin),
m.contact,
Expand Down Expand Up @@ -1775,8 +1792,9 @@ def job_offer():
id = d[0].id
bid_choices.append((
str(id),
'{}</td><td>{}</td><td>{}</td><td>{}</td><td>{}</td><td>{}'.format(
'{}</td><td><a href="/profile/{}">{}</a></td><td>{}</td><td>{}</td><td>{}</td><td>{}'.format(
job_link(b),
worker_msin,
b['Worker'],
get_average_user_rating_display(log, url, user, rein, worker_msin),
b['Description'],
Expand Down Expand Up @@ -2195,6 +2213,8 @@ def job_info_page(jobid):
except ValueError:
mediator_fee_btc = "NaN"

worker_msin = generate_sin(combined['Worker master address']) if 'Worker master address' in combined else ''

return render_template('job.html',
rein=rein,
user=user,
Expand All @@ -2203,9 +2223,13 @@ def job_info_page(jobid):
urls=urls,
state=state,
found=found,
fee=PersistConfig.get(rein, 'fee', 0.00025),
fee=PersistConfig.get(rein, 'fee', 0.001),
explorer=PersistConfig.get(rein, 'explorer', 'https://blockexplorer.com'),
unique=unique_documents,
job=combined,
job_creator_msin=generate_sin(combined['Job creator master address']),
mediator_msin=generate_sin(combined['Mediator master address']),
worker_msin=worker_msin,
mediator_fee_btc=mediator_fee_btc)


Expand Down Expand Up @@ -2363,9 +2387,13 @@ def job_bid():
continue

creator_msin = generate_sin(j['Job creator master address'])
row = '<a href="http://localhost:'+str(port)+'/job/{}">{}</a></td><td>{}</td><td>{}</td><td>{}</td><td>{}</td><td><span title="{}">{}</span></td><td>{}'
row = '<a href="http://localhost:'+str(port)+'/job/{}">{}</a></td>' +\
'<td><a href="/profile/{}">{}</a></td>' +\
'<td>{}</td><td>{}</td><td>{}</td>' +\
'<td><span title="{}">{}</span></td><td>{}'
job_ids.append((j['Job ID'], row.format(j['Job ID'],
j['Job name'],
creator_msin,
j['Job creator'],
get_average_user_rating_display(log, url, user, rein, creator_msin),
j['Description'],
Expand Down Expand Up @@ -2400,6 +2428,7 @@ def job_bid():
{'label': 'Job name', 'value_from': job},
{'label': 'Worker', 'value': user.name},
{'label': 'Worker contact', 'value': user.contact},
{'label': 'Worker msin', 'value': user.msin},
{'label': 'Worker delegate address', 'value': user.daddr},
{'label': 'Worker master address', 'value': user.maddr},
{'label': 'Description', 'value': form.description.data},
Expand Down
20 changes: 15 additions & 5 deletions rein/html/job.html
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,26 @@ <h4>Job Detail</h4>
<div class="row">
<div class="col-xs-3 well" style="margin-right:10px; margin-left:10px;">
<h5>Job creator</h5>
Name: <b>{{ job['Job creator'] }}</b><br />Contact: <a href="mailto:{{ job['Job creator contact'] }}">{{ job['Job creator contact'] }}</a><br />Master: <span title="{{ job['Job creator master address'] }}">{{ job['Job creator master address'][0:10] }}...{{ job['Job creator master address'][-8:] }}</span><br />
Name: <a href="/profile/{{ job_creator_msin }}">{{ job['Job creator'] }}</a><br />
Contact: <a href="mailto:{{ job['Job creator contact'] }}">{{ job['Job creator contact'] }}</a><br />
Direct payment address: <br /><a href="{{ explorer }}/address/{{ job['Job creator delegate address'] }}">
{{ job['Job creator delegate address'][0:17] }}<br />{{ job['Job creator delegate address'][17:] }}</a>
</div>
<div class="col-xs-3 well" style="margin-right:10px">
<h5>Mediator</h5>
Name: <b>{{ job['Mediator'] }}</b><br />Contact: <a href="mailto:{{ job['Mediator contact'] }}">{{ job['Mediator contact'] }}</a><br />Master: {{ job['Mediator master address'][0:10] }}...{{ job['Mediator master address'][-8:] }}<br />
Name: <a href="/profile/{{ mediator_msin }}">{{ job['Mediator'] }}</a><br />
Contact: <a href="mailto:{{ job['Mediator contact'] }}">{{ job['Mediator contact'] }}</a><br />
Direct payment address: <br /><a href="{{ explorer }}/address/{{ job['Mediator delegate address'] }}">
{{ job['Mediator delegate address'][0:17] }}<br />{{ job['Mediator delegate address'][17:] }}</a>

{% if 'Worker' in job %}
</div>
<div class="col-xs-3 well">
<h5>Worker</h5>
Name: <b>{{ job['Worker'] }}</b><br />Contact: <a href="mailto:{{ job['Worker contact'] }}">{{ job['Worker contact'] }}</a><br />Master: {{ job['Worker master address'][0:10] }}...{{ job['Worker master address'][-8:] }}
Name: <a href="/profile/{{ worker_msin }}">{{ job['Worker'] }}</a><br />
Contact: <a href="mailto:{{ job['Worker contact'] }}">{{ job['Worker contact'] }}</a><br />
Direct payment address: <br /><a href="{{ explorer }}/address/{{ job['Worker delegate address'] }}">
{{ job['Worker delegate address'][0:17] }}<br />{{ job['Worker delegate address'][17:] }}</a>
</div>
</div>

Expand All @@ -65,13 +75,13 @@ <h5>Payments</h5>
<div id="primary"></div>
</div>
<div class="col-xs-6 well" style="margin-right:10px; margin-left:10px;">
Primary escrow: <b>{{ job['Primary escrow address'] }}</b><icon class="qrcode"> should be funded with <b>{{ job['Bid amount (BTC)'] }} BTC</b> plus <b>{{ fee }}</b> for the closing transaction fee.
Primary escrow: <b><a href="{{ explorer }}/address/{{ job['Primary escrow address'] }}">{{ job['Primary escrow address'] }}</a></b><icon class="qrcode"> should be funded with <b>{{ job['Bid amount (BTC)'] }} BTC</b> plus <b>{{ fee }}</b> for the closing transaction fee.
</div>
</div>

<div class="row" style="margin-top: 10px;">
<div class="col-xs-6 well" style="margin-right:10px; margin-left:10px;">
Mediator escrow: <b>{{ job['Mediator escrow address'] }}</b><icon class="qrcode"> should be funded with <b>{{ mediator_fee_btc }} BTC</b> ({{ job['Mediator fee'] }}% of the above) plus <b>{{ fee }}</b> for the closing transaction fee.
Mediator escrow: <b><a href="{{ explorer }}/address/{{ job['Mediator escrow address'] }}">{{ job['Mediator escrow address'] }}</a></b><icon class="qrcode"> should be funded with <b>{{ mediator_fee_btc }} BTC</b> ({{ job['Mediator fee'] }}% of the above) plus <b>{{ fee }}</b> for the closing transaction fee.
</div>
<div class="col-xs-2" style="margin-right:10px">
<div class="qrcode">
Expand Down
18 changes: 12 additions & 6 deletions rein/html/ratings.html → rein/html/profile.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,24 @@

<br>
<div class="well">
<p>This page displays ratings received by <b>{{ user_rated }}</b> (msin: {{ msin }}).</p>
<h4>User Profile</h4>
<p>Name / handle: {{ user_rated }}<br />
Contact: <a href="mailto:{{ user.contact }}">{{ user.contact }}</a><br />
Master address: {{ user.maddr }}<br />
Direct payment address: <a href="{{ explorer }}/address/{{ user.daddr }}">{{ user.daddr }}</a><br />
SIN (<a href="https://en.bitcoin.it/wiki/Identity_protocol_v1">?</a>): {{ msin }}</p>

<p><div id="trustScoreDisplay"></div></p>

{% if display_trust_score %}
{% if display_trust_score %}
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
setTrustScore('{{ msin }}', 'trustScoreDisplay');
});
</script>
{% else %}
{% else %}
<p><button onclick="setTrustScore('{{ msin }}', 'trustScoreDisplay')">Calculate trust score</button></p>
{% endif %}
{% endif %}

<p>
<table class="table m-table table-bordered table-hover table-heading">
Expand All @@ -31,12 +37,12 @@
<tr>
<td>{{ rating.rating_value|safe }}</td>
<td>{{ rating.comments }}</td>
<td>{{ rating.rated_by_name }} - {{ rating.rated_by_rating|safe }}</a></td>
<td><a href="/profile/{{ rating.rated_by_msin }}">{{ rating.rated_by_name }}</a> - {{ rating.rated_by_rating|safe }}</a></td>
</tr>
{% endfor %}
</tbody>
</table>
</p>
</div>

{% endblock %}
{% endblock %}
22 changes: 12 additions & 10 deletions rein/html/rate.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,7 @@ <h3>Submit rating</h3>

<div class="form-group">
<label class="col-sm-4 control-label">{{ form.job_id.label }}</label>
<div class="col-sm-6">{{ form.job_id(class="form-control", data_toggle="tooltip", title="Unique job identifier", readonly=true) }}</div>
{{ render_error(form.job_id) }}
</div>

<div class="form-group">
<div class="btn-group col-sm-offset-4 col-sm-6" role="group">
<div class="col-sm-6 btn-group" role="group">
<button type="button" class="btn btn-default" onclick="lastJob()">
<span class="glyphicon glyphicon-chevron-left"></span>
</button>
Expand All @@ -36,13 +31,14 @@ <h3>Submit rating</h3>
</div>

<div class="form-group">
<label class="col-sm-4 control-label">{{ form.user_id.label }}</label>
<div class="col-sm-6">{{ form.user_id(class="form-control", data_toggle="tooltip", title="Unique user identifier: Secure Identity Number", readonly=true) }}</div>
{{ render_error(form.user_id) }}
<div class="col-sm-offset-4 col-sm-6" role="group">
{{ form.job_id(class="form-control", data_toggle="tooltip", title="Unique job identifier", readonly=true) }}</div>
{{ render_error(form.job_id) }}
</div>

<div class="form-group">
<div class="btn-group col-sm-offset-4 col-sm-6" role="group">
<label class="col-sm-4 control-label">{{ form.user_id.label }}</label>
<div class="col-sm-6 btn-group" role="group">
<button type="button" class="btn btn-default" onclick="lastUser()">
<span class="glyphicon glyphicon-chevron-left"></span>
</button>
Expand All @@ -53,6 +49,12 @@ <h3>Submit rating</h3>
</div>
</div>

<div class="form-group">
<div class="col-sm-offset-4 col-sm-6" role="group">
{{ form.user_id(class="form-control", data_toggle="tooltip", title="Unique user identifier: Secure Identity Number", readonly=true) }}</div>
{{ render_error(form.user_id) }}
</div>

<div class="form-group">
<label class="col-sm-4 control-label">{{ form.rating.label }}</label>
{{ form.rating(class="form-control") }}
Expand Down
3 changes: 2 additions & 1 deletion rein/lib/rating.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ def get_average_user_rating_display(log, url, user, rein, msin, cli=False):
return 'Not yet rated'

if not cli:
return '{} <i class="fa fa-star"></i> <small>(<a href="/ratings/{}">{}</a>)</small>'.format(rating[0], msin, rating[1])
return '{} <i class="fa fa-star"></i> <small>(<a href="/profile/{}">{}</a>)</small>'.format(rating[0], msin, rating[1])

return '{} Stars ({})'.format(rating[0], rating[1])

Expand All @@ -172,6 +172,7 @@ def get_all_user_ratings(log, url, user, rein, msin):
{
'rating_value': '{} <i class="fa fa-star"></i>'.format(float(rating['Rating'])),
'comments': rating['Comments'],
'rated_by_msin': rating['Rater msin'],
'rated_by_name': get_user_name(log, url, user, rein, rating['Rater msin']),
'rated_by_rating': get_average_user_rating_display(log, url, user, rein, rating['Rater msin'])
}
Expand Down
10 changes: 6 additions & 4 deletions rein/lib/transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
import urllib2, urllib
import json
from hashlib import sha256
api = "blocktrail" #handle this
from .bucket import Bucket
from .io import safe_get
from .persistconfig import PersistConfig
import click

def unspent_txins(address,testnet):

def unspent_txins(rein, address, testnet):
api = PersistConfig.get(rein, 'api', 'blockr')

if (api == "blockr"):
if testnet:
url = "https://tbtc.blockr.io/api/v1/address/unspent/"+str(address)
Expand Down Expand Up @@ -65,7 +67,7 @@ def partial_spend_p2sh (redeemScript,rein,daddr=None,alt_amount=None,alt_daddr=N
txin_redeemScript = CScript(x(redeemScript))
txin_scriptPubKey = txin_redeemScript.to_p2sh_scriptPubKey()
txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey)
(txins,total_value) = unspent_txins(txin_p2sh_address,rein.testnet)
(txins,total_value) = unspent_txins(rein, txin_p2sh_address,rein.testnet)
if len(txins)==0:
raise ValueError('Primary escrow is empty. Please inform client to add funds.')
txins_str = ""
Expand Down Expand Up @@ -101,7 +103,7 @@ def partial_spend_p2sh_mediator (redeemScript,rein,mediator_address,mediator_sig
txin_redeemScript = CScript(x(redeemScript))
txin_scriptPubKey = txin_redeemScript.to_p2sh_scriptPubKey()
txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey)
(txins,total_value) = unspent_txins(txin_p2sh_address,rein.testnet)
(txins,total_value) = unspent_txins(rein, txin_p2sh_address,rein.testnet)
if len(txins)==0:
raise ValueError('Mediator escrow is empty. Please inform client to add funds.')
txins_str = ""
Expand Down

0 comments on commit b46c7c3

Please sign in to comment.