Skip to content

Commit

Permalink
Identity management is implemented, tested, and connected, as is bala…
Browse files Browse the repository at this point in the history
…nce checking. Alpha Release 3.
  • Loading branch information
Romulus10 committed Oct 18, 2018
1 parent a3782de commit 10f115d
Show file tree
Hide file tree
Showing 11 changed files with 104 additions and 50 deletions.
34 changes: 27 additions & 7 deletions blockchain_message/src/blockchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,19 @@
from blockchain_message.src.core import Message, Contact


class OutOfIdentitiesException(Exception):
"""
Thrown when the system has run out of room for new identities.
"""

def __init__(self, message):
"""
Default constructor.
:param message: The text of the exception detail.
"""
super().__init__(message)


# noinspection PyUnresolvedReferences
class Blockchain(object):
"""
Expand All @@ -18,12 +31,12 @@ def __init__(self):
Sets up Ethereum interaction variables and compiles the contract, allowing web3 to call functions directly.
"""
with open('./.blkchnmsg/contract', 'r') as f:
self.addr = f.readline()
self.addr = f.readline().strip()
self.addr_2 = f.readline()
compiled = compile_files(['./../contract/contracts/blockchain_message.sol'])
compiled_manager = compile_files(["./contract/contracts/identity_manager.sol"])
compiled_manager = compile_files(["./../contract/contracts/identity_manager.sol"])
self.contract_interface = compiled['./../contract/contracts/blockchain_message.sol:BlckChnMsgStorage']
self.manager_interface = compiled_manager["./contract/contracts/identity_manager.sol:IdentityManager"]
self.manager_interface = compiled_manager["./../contract/contracts/identity_manager.sol:IdentityManager"]
self.w3 = Web3(HTTPProvider("http://localhost:7545"))
self.contract = self.w3.eth.contract(abi=self.contract_interface['abi'],
bytecode=self.contract_interface['bin'])
Expand All @@ -33,12 +46,19 @@ def __init__(self):
def get_identity(self, uname) -> int:
"""
:param uname:
:return:
:param uname: The username we need the address for.
:return: The unique identifier associated with uname.
"""
abi = self.contract_interface['abi']
abi = self.manager_interface['abi']
contract = self.w3.eth.contract(address=self.addr_2, abi=abi, ContractFactoryClass=ConciseContract)
return contract.get_identity(uname).call()
return contract.get_identity(uname)

def get_balance(self) -> float:
"""
:return: The current ETH balance.
"""
return self.w3.eth.getBalance(self.w3.eth.accounts[0])

def submit(self, message: Message):
"""
Expand Down
40 changes: 20 additions & 20 deletions blockchain_message/src/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def __commit(self):
def __max_msgid(self) -> int:
"""
:return:
:return: The current maximum message ID.
"""
m: int = -1
for x in self.messages:
Expand All @@ -76,10 +76,10 @@ def add_contact(self, addr: str, uname: str, email: str) -> bool:
"""
Adds a new contact object to the database.
:param uname:
:param addr:
:param email:
:return:
:param uname: The contact's uname.
:param addr: The address retrieved from the Identity Manager contract.
:param email: The contact's email address, used to verify correct identity.
:return: Whether or not the contact was created successfully.
"""
self.contacts.append(Contact(addr, uname, email))
self.__commit()
Expand All @@ -88,8 +88,8 @@ def add_contact(self, addr: str, uname: str, email: str) -> bool:
def read_contact(self, uname: str) -> Contact:
"""
:param uname:
:return:
:param uname: The username to read data for.
:return: The Contact object associated with the given username.
"""
for x in self.contacts:
if x.uname == uname:
Expand All @@ -99,8 +99,8 @@ def read_contact(self, uname: str) -> Contact:
def del_contact(self, name: str) -> bool:
"""
:param name:
:return:
:param name: The uname of the contact to be deleted.s
:return: Was the deletion successful?
"""
for x in self.contacts:
if x.uname is name:
Expand All @@ -113,12 +113,12 @@ def insert(self, to: Contact, fr: Contact, text: str, sign: str, verified: bool)
"""
Produces a message object and adds it to the internal database.
:param to:
:param fr:
:param text:
:param sign:
:param verified:
:return:
:param to: The Contact the message is being sent to.
:param fr: The Contact the message originated from.
:param text: The text of the message itself.
:param sign: The cryptographic signature of the unencrypted message text.
:param verified: Whether or not the message's signature has been verified successfully.
:return: The message object that has just been added to the database.
"""
m = Message(self.__max_msgid() + 1, to, fr, text, sign, verified)
self.messages.append(m)
Expand All @@ -128,8 +128,8 @@ def insert(self, to: Contact, fr: Contact, text: str, sign: str, verified: bool)
def delete(self, msgid: int) -> bool:
"""
:param msgid:
:return:
:param msgid: The ID of the message to delete.
:return: Deleted successfully?
"""
for x in self.messages:
if x.id is msgid:
Expand All @@ -141,8 +141,8 @@ def delete(self, msgid: int) -> bool:
def read(self, msgid: int) -> Message:
"""
:param msgid:
:return:
:param msgid: The ID of the message to read.
:return: The message corresponding to msgid.
"""
for x in self.messages:
if x.id is msgid:
Expand All @@ -151,6 +151,6 @@ def read(self, msgid: int) -> Message:

def message_index(self) -> int:
"""
:return:
:return: The highest current message index.
"""
return self.__max_msgid()
7 changes: 7 additions & 0 deletions blockchain_message/src/lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ def get_identity(self, uname) -> int:
"""
return self.b.get_identity(uname)

def get_balance(self) -> float:
"""
:return:
"""
return self.b.get_balance()

def pull_messages(self, uname: str) -> int:
"""
Downloads all new messages for the current user from the smart contract.
Expand Down
11 changes: 10 additions & 1 deletion client/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,12 @@ def new_contact(msg: BlockchainMessage):
:param msg: A BlockchainMessage object.
"""
print("Adding a new contact:")
addr = input("addr: ")
uname = input("uname: ")
email = input("email: ")
addr = msg.get_identity(uname)
if addr == 9999:
print(
"A new contact couldn't be created - the requested username doesn't exist, and the system is out of room.")
msg.send.add_contact(addr, uname, email)
msg.recv.add_contact(addr, uname, email)

Expand All @@ -74,6 +77,9 @@ def main():
email = input("email > ")
msg = BlockchainMessage(uname)
addr = msg.get_identity(uname)
if addr == 9999:
print(
"A new contact couldn't be created - the requested username doesn't exist, and the system is out of room.")
msg.send.add_contact(addr, uname, email)
msg.recv.add_contact(addr, uname, email)
done: bool = False
Expand All @@ -89,12 +95,15 @@ def main():
contacts(msg)
if cmd == "new-contact":
new_contact(msg)
if cmd == "balance":
print(msg.get_balance())
if cmd == "exit":
done = True
if cmd == "help":
print("""
\tbalance
\tcheck
\tread
\twrite
Expand Down
4 changes: 2 additions & 2 deletions contract/contracts/blockchain_message.sol
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
pragma solidity ^0.4.7;

contract BlckChnMsgStorage {
string[10][10] db;
uint256[10] lengths;
string[100][100] db;
uint256[100] lengths;

function store(uint key, uint to_user, string val) public {
db[to_user][key] = val;
Expand Down
14 changes: 9 additions & 5 deletions contract/contracts/identity_manager.sol
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
pragma solidity ^0.4.7;

contract IdentityManager {
string[10] users;
string[100] users;
uint latest;

function new_identity(string uname) public returns (uint) {

if (latest >= 100) return 9999;

users[latest] = uname;
latest++;
return latest;
}

function get_identity(string uname) public view returns (uint) {
uint result = 11;
function get_identity(string uname) public returns (uint) {
uint result = 999;

for (uint i = 0; i < 10; i++) {
for (uint i = 0; i < 100; i++) {
if (stringsEqual(users[i], uname)) {
result = i;
}
}

if (result == 11) {
if (result == 999) {
result = new_identity(uname);
}

Expand Down
12 changes: 8 additions & 4 deletions docs/design/blockchain_message.tex
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
\end{abstract}

\section{System Architectural Design}
The system's architecture is mostly based in the abstract standard for the client library (discussed in the \textbf{Component Architectural Design} section) and a set of \glsp{smart contract}\index{smart contracts} which create the actual body of the system.
The system's architecture is mostly based in the abstract standard for the client library (discussed in the \textbf{Component Architectural Design} section) and a set of \glspl{smart contract}\index{smart contracts} which create the actual body of the system.

\subsection{Accomplished Functionality}
\subsubsection{Communication Implementation}
Expand All @@ -42,10 +42,10 @@ \subsubsection{Communication Implementation}
\label{fig:messagestorage}
\end{figure}

\subsection{Functionality Goals}
\subsubsection{Identity Management}
\gls{Identity management} is one of the high-level stretch goals outlined in the original proposal, and will need a new \gls{smart contract}\index{smart contract} written which will be capable of attaching a single unique user id (\texttt{addr}) with a single username/email/password set, thereby preventing messages from being sent to the wrong person, similar to a phone number. The \texttt{BlckchnMsgStorage} contract itself only deals with the user's address\index{address}, and without some kind of user management and address\index{address} assignment to act as a key any person would be able to tie in to any address\index{address} and download every message in that address\index{address}'s associated ``mailbox''. The smart contract will contain a key-value lookup table where every new login (username, email, password) is assigned an address\index{address} which is immutably tied to that username. When adding a contact, the only values supplied will be a username and email address\index{address}, which the identity management contract will use to retrieve an address\index{address} which is never exposed to the end user.
\gls{Identity management} is one of the high-level stretch goals outlined in the original proposal, and will need a new \gls{smart contract}\index{smart contract} written which will be capable of attaching a single unique user id (\texttt{addr}) with a single username/email/password set, thereby preventing messages from being sent to the wrong person, similar to a phone number. The \texttt{BlckchnMsgStorage} contract itself only deals with the user's address\index{address}, and without some kind of user management and address\index{address} assignment to act as a key any person would be able to tie in to any address\index{address} and download every message in that address\index{address}'s associated ``mailbox''. The smart contract will contain a key-value lookup table where every new login is assigned an address\index{address} which is immutably tied to that username. When adding a contact, the only values supplied will be a username and email address\index{address}, which the identity management contract will use to retrieve an address\index{address} which is never exposed to the end user.

\subsection{Functionality Goals}
\subsubsection{Key Management}
Key management is usually handled through well-known servers set up specifically for distributing public keys. Because the keys used with this system are not OpenPGP-standardized, this method may not work as cleanly. Further work will be done to determine the remote key management system that makes the most sense for this platform. Internally to a client application, keys are read from files and are then stored in memory as binary public key\index{public key} objects. Each implementation will require its own language's approach to this, for example the Android app will use net.java.Security.PublicKey\index{PublicKey} and the Python implementation (CLI\index{CLI}) will use rsa.PublicKey\index{PublicKey}, both from their language's standard library. Keys, in the initial release of the application, must be exported (either by manually copying the keyfile from the keys directory or by using the eventual Export functionality)\footnote{At the time of writing, the ``Import'' and ``Export'' functionality groups are not yet implemented. When every basic feature of the applications is in place and working, abstraction functions like these will be added.} and sent (by email or similar medium) to the intended contact, who will then move it into their own keys directory (either manually or by using the eventual Import functionality) to be imported when the new Contact object is created.

Expand All @@ -54,6 +54,10 @@ \section{Component Architectural Design}
\subsection{Blockchain Communication}
The Blockchain module is used to send and retrieve message packets serialized as strings.

\subsubsection{def get\_identity(self, uname: str) -> int}
Either produces a new address by which a new user can be contacted or retrieves an existing user's unique address.
\subsubsection{def get\_balance(self) -> float}
Returns the volume of Ethereum the user has in their account.
\subsubsection{def submit(self, message: Message)}
Produces a message packet from a database Message object and transmits it to the \gls{blockchain}\index{blockchain}.
\subsubsection{def retrieve(user: Contact, last\_message: int, contact\_list: List[Contact]) -> List[Message]}
Expand Down Expand Up @@ -104,7 +108,7 @@ \subsection{Graphical/Mobile}
\section{Help System Design}

\subsection{CLI\index{CLI}}
The CLI\index{CLI} version will include a standard \verb|help| directive that will print out the full list of commands available with usage details for every component in the style of classical *nix command help dialogues.
The CLI\index{CLI} version will include a standard \verb|help| directive that will print out the full list of commands available with usage details for every component in the style of classical *nix command help dialogues. The user manual will also contain specific information on the usage of the CLI version, since that will most directly reflect the functionality described in the original proposal.

\subsection{Graphical/Mobile}
The graphical implementations (starting with the Android app) will contain a help menu, clearly labeled, that will display a clear overview of how every component of the UI will function as well as basic overviews of cryptographical functions and how to interact with an individual \gls{Ethereum}\index{Ethereum} account.
Expand Down
3 changes: 2 additions & 1 deletion install
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
echo 'This version of the install script only works on Ubuntu. If you know what you're doing, you can modify it to work under any Linux distribution.'

if [ "$EUID" -ne 0 ]
then echo "Please run as root - 'sudo install'"
then echo "Please run as root - 'sudo ./install'"
exit
fi

Expand Down Expand Up @@ -75,5 +75,6 @@ pip install toolz
pip install urllib3
pip install web3
pip install websockets
pip install .

deactivate
25 changes: 17 additions & 8 deletions proof/src/main_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,29 @@
from solc import compile_files
from web3 import Web3, HTTPProvider

compiled = compile_files(["./contract/contracts/blockchain_message.sol"])
contract_interface = compiled['./contract/contracts/blockchain_message.sol:BlckChnMsgStorage']
compiled_storage = compile_files(["./contract/contracts/blockchain_message.sol"])
compiled_manager = compile_files(["./contract/contracts/identity_manager.sol"])
storage_interface = compiled_storage['./contract/contracts/blockchain_message.sol:BlckChnMsgStorage']
manager_interface = compiled_manager['./contract/contracts/identity_manager.sol:IdentityManager']

w3 = Web3(HTTPProvider("http://localhost:7545"))

print(w3.eth.getBlock('latest').number)
contract = w3.eth.contract(abi=contract_interface['abi'], bytecode=contract_interface['bin'])
storage_contract = w3.eth.contract(abi=storage_interface['abi'], bytecode=storage_interface['bin'])
manager_contract = w3.eth.contract(abi=manager_interface['abi'], bytecode=manager_interface['bin'])

tx = contract.constructor().transact(transaction={'from': w3.eth.accounts[0], 'gas': 5000000})
tx_a = storage_contract.constructor().transact(transaction={'from': w3.eth.accounts[0], 'gas': 5000000})
tx_b = manager_contract.constructor().transact(transaction={'from': w3.eth.accounts[0], 'gas': 5000000})

receipt = w3.eth.getTransactionReceipt(tx)
addr = receipt['contractAddress']
receipt_a = w3.eth.getTransactionReceipt(tx_a)
receipt_b = w3.eth.getTransactionReceipt(tx_b)

print("Address: {}".format(addr))
addr_a = receipt_a['contractAddress']
addr_b = receipt_b['contractAddress']

print("Address: {}".format(addr_a))
print("Address: {}".format(addr_b))

with open('./test/.blkchnmsg/contract', 'w') as f:
f.write(addr)
f.write(addr_a + "\n")
f.write(addr_b)
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

setup(
name='blockchain_message',
version='0.1.0a2',
version='0.1.0a3',
packages=['test', 'client', 'blockchain_message', 'blockchain_message.src'],
url='',
license='GPL',
author='Sean Batzel',
author_email='[email protected]',
description=''
description='An email-like service that uses Ethereum as a decentralized email service.'
)
Empty file added web/__init__.py
Empty file.

0 comments on commit 10f115d

Please sign in to comment.