Пример #1
0
 def delete_contract(self, request):
     if "id" in request.args:
         c = Contract(hash_value=unhexlify(request.args["id"][0]))
         for keyword in c.contract["vendor_offer"]["listing"]["item"]["keywords"]:
             self.kserver.delete(keyword.lower(), c.get_contract_id(),
                                 KeyChain().signing_key.sign(c.get_contract_id())[:64])
         c.delete()
Пример #2
0
 def __init__(self, mserver, kserver, protocol):
     self.mserver = mserver
     self.kserver = kserver
     self.protocol = protocol
     self.db = mserver.db
     self.keychain = KeyChain(self.db)
     APIResource.__init__(self)
Пример #3
0
 def parse_results(values):
     if values is not None:
         for v in values:
             try:
                 val = Value()
                 val.ParseFromString(v)
                 n = objects.Node()
                 n.ParseFromString(val.serializedData)
                 node_to_ask = Node(
                     n.guid, n.nodeAddress.ip, n.nodeAddress.port,
                     n.signedPublicKey,
                     None if not n.HasField("relayAddress") else
                     (n.relayAddress.ip, n.relayAddress.port),
                     n.natType, n.vendor)
                 if n.guid == KeyChain(self.factory.db).guid:
                     proto = self.factory.db.ListingsStore().get_proto()
                     l = Listings()
                     l.ParseFromString(proto)
                     for listing in l.listing:
                         if listing.contract_hash == val.valueKey:
                             respond(listing, node_to_ask)
                 else:
                     self.factory.mserver.get_contract_metadata(node_to_ask, val.valueKey)\
                         .addCallback(respond, node_to_ask)
             except Exception:
                 pass
Пример #4
0
 def create(self, name, location, handle=None):
     self.profile.name = name
     self.profile.location = location
     if handle is not None:
         self.profile.handle = handle
     self.profile.encryption_key = KeyChain().encryption_pubkey
     self.db.set_proto(self.profile.SerializeToString())
Пример #5
0
    def release_funds(self, order_id):
        """
        This function should be called to release funds from a disputed contract after
        the moderator has resolved the dispute and provided his signature.
        """
        if os.path.exists(DATA_FOLDER + "purchases/in progress/" + order_id + ".json"):
            file_path = DATA_FOLDER + "purchases/trade receipts/" + order_id + ".json"
            outpoints = pickle.loads(self.db.Purchases().get_outpoint(order_id))
        elif os.path.exists(DATA_FOLDER + "store/contracts/in progress/" + order_id + ".json"):
            file_path = DATA_FOLDER + "store/contracts/in progress/" + order_id + ".json"
            outpoints = pickle.loads(self.db.Sales().get_outpoint(order_id))

        with open(file_path, 'r') as filename:
            contract = json.load(filename, object_pairs_hook=OrderedDict)

        vendor_address = contract["vendor_order_confirmation"]["invoice"]["payout"]["address"]
        buyer_address = contract["buyer_order"]["order"]["refund_address"]

        for moderator in contract["vendor_offer"]["listing"]["moderators"]:
            if moderator["guid"] == contract["buyer_order"]["order"]["moderator"]:
                masterkey_m = moderator["pubkeys"]["bitcoin"]["key"]

        outputs = []

        outputs.append({'value': contract["dispute_resolution"]["resolution"]["moderator_fee"],
                        'address': contract["dispute_resolution"]["resolution"]["moderator_address"]})

        if "buyer_payout" in contract["dispute_resolution"]["resolution"]:
            outputs.append({'value': contract["dispute_resolution"]["resolution"]["buyer_payout"],
                            'address': buyer_address})

        if "vendor_payout" in contract["dispute_resolution"]["resolution"]:
            outputs.append({'value': contract["dispute_resolution"]["resolution"]["vendor_payout"],
                            'address': vendor_address})

        tx = bitcoin.mktx(outpoints, outputs)
        signatures = []
        chaincode = contract["buyer_order"]["order"]["payment"]["chaincode"]
        redeem_script = str(contract["buyer_order"]["order"]["payment"]["redeem_script"])
        masterkey = bitcoin.bip32_extract_key(KeyChain(self.db).bitcoin_master_privkey)
        childkey = derive_childkey(masterkey, chaincode, bitcoin.MAINNET_PRIVATE)

        mod_key = derive_childkey(masterkey_m, chaincode)

        valid_inputs = 0
        for index in range(0, len(outpoints)):
            sig = bitcoin.multisign(tx, index, redeem_script, childkey)
            signatures.append({"input_index": index, "signature": sig})
            for s in contract["dispute_resolution"]["resolution"]["tx_signatures"]:
                if s["input_index"] == index:
                    if bitcoin.verify_tx_input(tx, index, redeem_script, s["signature"], mod_key):
                        tx = bitcoin.apply_multisignatures(tx, index, str(redeem_script),
                                                           sig, str(s["signature"]))
                        valid_inputs += 1

        if valid_inputs == len(outpoints):
            self.log.info("Broadcasting payout tx %s to network" % bitcoin.txhash(tx))
            self.protocol.multiplexer.blockchain.broadcast(tx)
        else:
            raise Exception("Failed to reconstruct transaction with moderator signature.")
Пример #6
0
 def set_settings(self, request):
     try:
         settings = self.db.Settings()
         settings.update(
             request.args["refund_address"][0],
             request.args["currency_code"][0], request.args["country"][0],
             request.args["language"][0], request.args["time_zone"][0],
             1 if bool(request.args["notifications"][0]) else 0,
             request.args["ship_to_name"][0],
             request.args["ship_to_street"][0],
             request.args["ship_to_city"][0],
             request.args["ship_to_state"][0],
             request.args["ship_to_postal_code"][0],
             request.args["ship_to_country"][0],
             pickle.dumps(request.args["blocked"]),
             request.args["libbitcoin_server"][0],
             1 if bool(request.args["ssl"][0]) else 0,
             KeyChain(self.db).guid_privkey.encode("hex"),
             request.args["server_url"][0],
             request.args["terms_conditions"][0],
             request.args["refund_policy"][0])
         request.write(json.dumps({"success": True}, indent=4))
         request.finish()
         return server.NOT_DONE_YET
     except Exception, e:
         request.write(
             json.dumps({
                 "success": False,
                 "reason": e.message
             }, indent=4))
         request.finish()
         return server.NOT_DONE_YET
Пример #7
0
 def update_profile(self, request):
     p = Profile()
     if not p.get().encryption_key \
             and "name" not in request.args \
             and "location" not in request.args:
         return "False"
     u = objects.Profile()
     if "name" in request.args:
         u.name = request.args["name"][0]
     if "location" in request.args:
         # This needs to be formatted. Either here or from the UI.
         u.location = CountryCode.Value(request.args["location"][0].upper())
     if "handle" in request.args:
         u.handle = request.args["handle"][0]
     if "about" in request.args:
         u.about = request.args["about"][0]
     if "nsfw" in request.args:
         u.nsfw = True
     if "vendor" in request.args:
         u.vendor = True
     if "moderator" in request.args:
         u.moderator = True
     if "website" in request.args:
         u.website = request.args["website"][0]
     if "email" in request.args:
         u.email = request.args["email"][0]
     if "avatar" in request.args:
         with open(DATA_FOLDER + "store/avatar", 'wb') as outfile:
             outfile.write(request.args["avatar"][0])
         avatar_hash = digest(request.args["avatar"][0])
         HashMap().insert(avatar_hash, DATA_FOLDER + "store/avatar")
         u.avatar_hash = avatar_hash
     if "header" in request.args:
         with open(DATA_FOLDER + "store/header", 'wb') as outfile:
             outfile.write(request.args["header"][0])
         header_hash = digest(request.args["header"][0])
         HashMap().insert(header_hash, DATA_FOLDER + "store/header")
         u.header_hash = header_hash
     if "pgp_key" in request.args and "signature" in request.args:
         p.add_pgp_key(request.args["pgp_key"][0],
                       request.args["signature"][0],
                       KeyChain().guid.encode("hex"))
     u.encryption_key = KeyChain().encryption_pubkey
     p.update(u)
Пример #8
0
        def parse_response(moderators):
            if moderators is not None:
                m.clear_all()

                def parse_profile(profile, node):
                    if profile is not None:
                        m.save_moderator(
                            node.id.encode("hex"), node.signed_pubkey,
                            profile.encryption_key.public_key,
                            profile.encryption_key.signature,
                            profile.bitcoin_key.public_key,
                            profile.bitcoin_key.signature, profile.name,
                            profile.avatar_hash, profile.moderation_fee,
                            profile.handle, profile.short_description)
                        moderator = {
                            "id": message_id,
                            "moderator": {
                                "guid": node.id.encode("hex"),
                                "name": profile.name,
                                "handle": profile.handle,
                                "short_description": profile.short_description,
                                "avatar_hash":
                                profile.avatar_hash.encode("hex"),
                                "about": profile.about,
                                "fee": profile.moderation_fee
                            }
                        }
                        self.sendMessage(json.dumps(moderator, indent=4),
                                         False)
                    else:
                        m.delete_moderator(node.id)

                for mod in moderators:
                    try:
                        val = objects.Value()
                        val.ParseFromString(mod)
                        n = objects.Node()
                        n.ParseFromString(val.serializedData)
                        node_to_ask = Node(
                            n.guid, n.nodeAddress.ip, n.nodeAddress.port,
                            n.signedPublicKey,
                            None if not n.HasField("relayAddress") else
                            (n.relayAddress.ip, n.relayAddress.port),
                            n.natType, n.vendor)
                        if n.guid == KeyChain(self.factory.db).guid:
                            parse_profile(
                                Profile(self.factory.db).get(), node_to_ask)
                        else:
                            self.factory.mserver.get_profile(node_to_ask)\
                                .addCallback(parse_profile, node_to_ask)
                    except Exception:
                        pass
Пример #9
0
    def __init__(self,
                 database,
                 contract=None,
                 hash_value=None,
                 testnet=False):
        """
        This class can be instantiated with either an `OrderedDict` or a hash
        of a contract. If a hash is used, we will load the contract from either
        the file system or cache.

        Alternatively, pass in no parameters if the intent is to create a new
        contract.

        Args:
            contract: an `OrderedDict` containing a filled out json contract
            hash: a hash160 (in raw bytes) of a contract
            testnet: is this contract on the testnet
        """
        self.db = database
        self.keychain = KeyChain(self.db)
        if contract is not None:
            self.contract = contract
        elif hash_value is not None:
            try:
                file_path = self.db.HashMap().get_file(hash_value)
                if file_path is None:
                    file_path = DATA_FOLDER + "cache/" + hexlify(hash_value)
                with open(file_path, 'r') as filename:
                    self.contract = json.load(filename,
                                              object_pairs_hook=OrderedDict)
            except Exception:
                try:
                    file_path = DATA_FOLDER + "purchases/in progress/" + hexlify(
                        hash_value) + ".json"
                    with open(file_path, 'r') as filename:
                        self.contract = json.load(
                            filename, object_pairs_hook=OrderedDict)
                except Exception:
                    self.contract = {}
        else:
            self.contract = {}
        self.log = Logger(system=self)

        # used when purchasing this contract
        self.testnet = testnet
        self.ws = None
        self.blockchain = None
        self.amount_funded = 0
        self.received_txs = []
        self.timeout = None
        self.is_purchase = False
        self.outpoints = []
Пример #10
0
    def make_moderator(self):
        """
        Set self as a moderator in the DHT.
        """

        u = objects.Profile()
        k = u.PublicKey()
        k.public_key = bitcoin.bip32_deserialize(KeyChain(self.db).bitcoin_master_pubkey)[5]
        k.signature = self.signing_key.sign(k.public_key)[:64]
        u.bitcoin_key.MergeFrom(k)
        u.moderator = True
        Profile(self.db).update(u)
        proto = self.kserver.node.getProto().SerializeToString()
        self.kserver.set(digest("moderators"), digest(proto), proto)
Пример #11
0
 def addpgpkey():
     parser = argparse.ArgumentParser(
         description="Add a pgp key to the profile.",
         usage='''usage:
 networkcli.py addpgpkey -k KEY, -s SIGNATURE''')
     parser.add_argument('-k', '--key', help="path to the key file")
     parser.add_argument('-s',
                         '--signature',
                         help="path to the signature file")
     args = parser.parse_args(sys.argv[2:])
     with open(args.key, "r") as filename:
         key = filename.read()
     with open(args.signature, "r") as filename:
         sig = filename.read()
     p = Profile()
     print p.add_pgp_key(key, sig, KeyChain().guid.encode("hex"))
Пример #12
0
 def setprofile():
     parser = argparse.ArgumentParser(
         description="Sets a profile in the database.",
         usage='''usage:
 networkcli.py setprofile [options]''')
     parser.add_argument('-n', '--name', help="the name of the user/store")
     parser.add_argument('-o', '--onename', help="the onename id")
     parser.add_argument('-a',
                         '--avatar',
                         help="the file path to the avatar image")
     parser.add_argument('-hd',
                         '--header',
                         help="the file path to the header image")
     parser.add_argument(
         '-c',
         '--country',
         help=
         "a string consisting of country from protos.countries.CountryCode")
     # we could add all the fields here but this is good enough to test.
     args = parser.parse_args(sys.argv[2:])
     p = Profile()
     u = objects.Profile()
     h = HashMap()
     if args.name is not None:
         u.name = args.name
     if args.country is not None:
         u.location = countries.CountryCode.Value(args.country.upper())
     if args.onename is not None:
         u.handle = args.onename
     if args.avatar is not None:
         with open(args.avatar, "r") as filename:
             image = filename.read()
         hash_value = digest(image)
         u.avatar_hash = hash_value
         h.insert(hash_value, args.avatar)
     if args.header is not None:
         with open(args.header, "r") as filename:
             image = filename.read()
         hash_value = digest(image)
         u.header_hash = hash_value
         h.insert(hash_value, args.header)
     u.encryption_key = KeyChain().encryption_pubkey
     p.update(u)
Пример #13
0
 def parse_profile(profile):
     if profile is not None:
         profile_json = {
             "profile": {
                 "name": profile.name,
                 "location": str(CountryCode.Name(profile.location)),
                 "enryption_key": profile.encryption_key.encode("hex"),
                 "nsfw": profile.nsfw,
                 "vendor": profile.vendor,
                 "moderator": profile.moderator,
                 "handle": profile.handle,
                 "about": profile.about,
                 "website": profile.website,
                 "email": profile.email,
                 "primary_color": profile.primary_color,
                 "secondary_color": profile.secondary_color,
                 "background_color": profile.background_color,
                 "text_color": profile.text_color,
                 "pgp_key": profile.pgp_key.publicKey,
                 "avatar_hash": profile.avatar_hash.encode("hex"),
                 "header_hash": profile.header_hash.encode("hex"),
                 "social_accounts": {}
             }
         }
         if "guid" in request.args:
             profile_json["profile"]["guid"] = request.args["guid"][0]
         else:
             profile_json["profile"]["guid"] = KeyChain().guid.encode(
                 "hex")
         for account in profile.social:
             profile_json["profile"]["social_accounts"][str(
                 objects.Profile.SocialAccount.SocialType.Name(
                     account.type)).lower()] = {
                         "username": account.username,
                         "proof_url": account.proof_url
                     }
         request.setHeader('content-type', "application/json")
         request.write(json.dumps(profile_json, indent=4))
         request.finish()
     else:
         request.write(NoResource().render(request))
         request.finish()
Пример #14
0
def run(*args):
    TESTNET = args[0]

    # database
    db = Database(TESTNET)

    # key generation
    keys = KeyChain(db)

    # logging
    # TODO: prune this log file and prevent it from getting too large?
    logFile = logfile.LogFile.fromFullPath(DATA_FOLDER + "debug.log")
    log.addObserver(FileLogObserver(logFile, level=args[1]).emit)
    log.addObserver(FileLogObserver(level=args[1]).emit)
    logger = Logger(system="OpenBazaard")

    # NAT traversal
    port = args[2]
    PortMapper().add_port_mapping(port, port, 'UDP')
    logger.info("Finding NAT Type...")
    try:
        response = stun.get_ip_info(source_port=port)
    except Exception:
        response = stun.get_ip_info()
    logger.info("%s on %s:%s" % (response[0], response[1], response[2]))
    ip_address = response[1]
    port = response[2]

    # TODO: use TURN if symmetric NAT

    def on_bootstrap_complete(resp):
        logger.info("bootstrap complete, downloading outstanding messages...")
        mlistener = MessageListenerImpl(ws_factory, db)
        mserver.get_messages(mlistener)
        mserver.protocol.add_listener(mlistener)
        nlistener = NotificationListenerImpl(ws_factory, db)
        mserver.protocol.add_listener(nlistener)

        # TODO: ping seed node to establish connection if not full cone NAT

        # TODO: after bootstrap run through any pending contracts and see if the bitcoin address
        # has been funded, if not listen on the address and start the 10 minute delete timer.

    protocol = OpenBazaarProtocol((ip_address, port), testnet=TESTNET)

    # kademlia
    node = Node(keys.guid,
                ip_address,
                port,
                signed_pubkey=keys.guid_signed_pubkey,
                vendor=Profile(db).get().vendor)

    storage = ForgetfulStorage() if TESTNET else PersistentStorage(db.DATABASE)

    try:
        kserver = Server.loadState(DATA_FOLDER + 'cache.pickle',
                                   ip_address,
                                   port,
                                   protocol,
                                   db,
                                   on_bootstrap_complete,
                                   storage=storage)
    except Exception:
        kserver = Server(node, db, KSIZE, ALPHA, storage=storage)
        kserver.protocol.connect_multiplexer(protocol)
        kserver.bootstrap(
            kserver.querySeed("seed.openbazaar.org:8080",
                              "5b44be5c18ced1bc9400fe5e79c8ab90204f06bebacc04dd9c70a95eaca6e117"))\
            .addCallback(on_bootstrap_complete)
        # TODO: load seeds from config file
    kserver.saveStateRegularly(DATA_FOLDER + 'cache.pickle', 10)
    protocol.register_processor(kserver.protocol)

    # market
    mserver = network.Server(kserver, keys.signing_key, db)
    mserver.protocol.connect_multiplexer(protocol)
    protocol.register_processor(mserver.protocol)

    reactor.listenUDP(port, protocol)

    # websockets api
    ws_factory = WSFactory("ws://127.0.0.1:18466", mserver, kserver)
    ws_factory.protocol = WSProtocol
    ws_factory.setProtocolOptions(allowHixie76=True)
    listenWS(ws_factory)
    webdir = File(".")
    web = Site(webdir)
    reactor.listenTCP(9000, web, interface=args[4])

    # rest api
    api = OpenBazaarAPI(mserver, kserver, protocol)
    site = Site(api, timeout=None)
    reactor.listenTCP(18469, site, interface=args[3])

    # TODO: add optional SSL on rest and websocket servers

    # blockchain
    # TODO: listen on the libbitcoin heartbeat port instead fetching height
    def height_fetched(ec, height):
        # TODO: re-broadcast any unconfirmed txs in the db using height to find confirmation status
        logger.info("Libbitcoin server online")
        try:
            timeout.cancel()
        except Exception:
            pass

    def timeout(client):
        logger.critical("Libbitcoin server offline")
        client = None

    if TESTNET:
        libbitcoin_client = LibbitcoinClient(
            "tcp://libbitcoin2.openbazaar.org:9091")
    else:
        libbitcoin_client = LibbitcoinClient(
            "tcp://libbitcoin1.openbazaar.org:9091")

    # TODO: load libbitcoin server url from config file

    libbitcoin_client.fetch_last_height(height_fetched)
    timeout = reactor.callLater(7, timeout, libbitcoin_client)

    protocol.set_servers(ws_factory, libbitcoin_client)

    reactor.run()
Пример #15
0
# stun
print "Finding NAT Type.."
response = stun.get_ip_info(stun_host='seed.openbazaar.org',
                            stun_port=3478,
                            source_port=0)
print "%s on %s:%s" % (response[0], response[1], response[2])
ip_address = response[1]
port = response[2]

# database
if not os.path.isfile(DATABASE):
    create_database()

# key generation
keys = KeyChain()


def on_bootstrap_complete(resp):
    mlistener = MessageListenerImpl(ws_factory)
    mserver.get_messages(mlistener)
    mserver.protocol.add_listener(mlistener)
    nlistener = NotificationListenerImpl(ws_factory)
    mserver.protocol.add_listener(nlistener)


protocol = OpenBazaarProtocol((ip_address, port))

# kademlia
node = Node(keys.guid, ip_address, port, signed_pubkey=keys.guid_signed_pubkey)
Пример #16
0
from dht.node import Node
from dht.network import Server
from dht.crawling import NodeSpiderCrawl
from dht.utils import digest, deferredDict
from protos import objects
from wireprotocol import OpenBazaarProtocol
from market import network
from keyutils.keys import KeyChain

sys.path.append(os.path.dirname(__file__))
application = service.Application("OpenBazaar_seed_server")
application.setComponent(ILogObserver,
                         log.FileLogObserver(sys.stdout, log.INFO).emit)

# Load the keys
keychain = KeyChain()
if os.path.isfile('keys.pickle'):
    keys = pickle.load(open("keys.pickle", "r"))
    signing_key_hex = keys["signing_privkey"]
    signing_key = nacl.signing.SigningKey(signing_key_hex,
                                          encoder=nacl.encoding.HexEncoder)
else:
    signing_key = nacl.signing.SigningKey.generate()
    keys = {
        'signing_privkey':
        signing_key.encode(encoder=nacl.encoding.HexEncoder),
        'signing_pubkey':
        signing_key.verify_key.encode(encoder=nacl.encoding.HexEncoder)
    }
    pickle.dump(keys, open("keys.pickle", "wb"))
Пример #17
0
def process_dispute(contract, db, message_listener, notification_listener,
                    testnet):
    """
    This function processes a dispute message received from another node. It checks the
    contract to see if this a dispute for a purchase we made, a dispute for one of our
    sales, or a new case if we are the moderator.

    If it's a purchase or sale it will
    update the order status to disputed and push a notification to the listener.

    If it's a new case it will validate the contract, create a new case in the db,
    and push a notification to the listener.

    Args:
        contract: a json contract of the current order state. Should have a "dispute"
            object attached with dispute info.
        db: a `Database` object.
        message_listener: a `MessageListenerImpl` object.
        notification_listener: a `NotificationListenerImpl` object.
        testnet: `bool` of whether we're on testnet or not.
    """
    tmp_contract = contract
    if "vendor_order_confirmation" in tmp_contract:
        del tmp_contract["vendor_order_confirmation"]
    if "buyer_receipt" in tmp_contract:
        del tmp_contract["buyer_receipt"]

    order_id = digest(json.dumps(tmp_contract, indent=4)).encode("hex")
    own_guid = KeyChain(db).guid.encode("hex")

    if contract["dispute"]["info"]["guid"] == contract["vendor_offer"][
            "listing"]["id"]["guid"]:
        guid = unhexlify(contract["vendor_offer"]["listing"]["id"]["guid"])
        signing_key = unhexlify(
            contract["vendor_offer"]["listing"]["id"]["pubkeys"]["guid"])
        if "blockchain_id" in contract["vendor_offer"]["listing"]["id"]:
            handle = contract["vendor_offer"]["listing"]["id"]["blockchain_id"]
        else:
            handle = ""
        encryption_key = unhexlify(
            contract["vendor_offer"]["listing"]["id"]["pubkeys"]["encryption"])
        proof_sig = contract["dispute"]["info"]["proof_sig"]
    elif contract["dispute"]["info"]["guid"] == contract["buyer_order"][
            "order"]["id"]["guid"]:
        guid = unhexlify(contract["buyer_order"]["order"]["id"]["guid"])
        signing_key = unhexlify(
            contract["buyer_order"]["order"]["id"]["pubkeys"]["guid"])
        if "blockchain_id" in contract["buyer_order"]["order"]["id"]:
            handle = contract["buyer_order"]["order"]["id"]["blockchain_id"]
        else:
            handle = ""
        encryption_key = unhexlify(
            contract["buyer_order"]["order"]["id"]["pubkeys"]["encryption"])
        proof_sig = None
    else:
        raise Exception("Dispute guid not in contract")

    verify_key = nacl.signing.VerifyKey(signing_key)
    verify_key.verify(json.dumps(contract["dispute"]["info"], indent=4),
                      contract["dispute"]["signature"])

    p = PlaintextMessage()
    p.sender_guid = guid
    p.handle = handle
    p.signed_pubkey = signing_key
    p.encryption_pubkey = encryption_key
    p.subject = order_id
    p.type = PlaintextMessage.Type.Value("DISPUTE_OPEN")
    p.message = contract["dispute"]["info"]["claim"]
    p.timestamp = time.time()
    p.avatar_hash = contract["dispute"]["info"]["avatar_hash"]

    if db.Purchases().get_purchase(order_id) is not None:
        db.Purchases().update_status(order_id, 4)

    elif db.Sales().get_sale(order_id) is not None:
        db.Purchases().update_status(order_id, 4)

    elif "moderators" in contract["vendor_offer"]["listing"]:
        # TODO: make sure a case isn't already open in the db
        is_selected = False
        for moderator in contract["vendor_offer"]["listing"]["moderators"]:
            if moderator["guid"] == own_guid and contract["buyer_order"][
                    "order"]["moderator"] == own_guid:
                is_selected = True
        if not is_selected:
            raise Exception("Not a moderator for this contract")
        else:
            if "blockchain_id" in contract["vendor_offer"]["listing"]["id"]:
                vendor = contract["vendor_offer"]["listing"]["id"][
                    "blockchain_id"]
            else:
                vendor = contract["vendor_offer"]["listing"]["id"]["guid"]
            if "blockchain_id" in contract["buyer_order"]["order"]["id"]:
                buyer = contract["buyer_order"]["order"]["id"]["blockchain_id"]
            else:
                buyer = contract["buyer_order"]["order"]["id"]["guid"]

            c = Contract(db, contract=contract, testnet=testnet)

            validation_failures = c.validate_for_moderation(proof_sig)

            db.Cases().new_case(
                order_id, contract["vendor_offer"]["listing"]["item"]["title"],
                time.time(), contract["buyer_order"]["order"]["date"],
                contract["buyer_order"]["order"],
                float(contract["buyer_order"]["order"]["payment"]["amount"]),
                contract["vendor_offer"]["listing"]["item"]["image_hashes"][0],
                buyer, vendor, json.dumps(validation_failures),
                contract["dispute"]["info"]["claim"])

            with open(DATA_FOLDER + "cases/" + order_id + ".json",
                      'wb') as outfile:
                outfile.write(json.dumps(contract, indent=4))
    else:
        raise Exception("Order ID for dispute not found")

    message_listener.notify(p, "")
    notification_listener.notify(
        guid, handle, "dispute_open", order_id,
        contract["vendor_offer"]["listing"]["item"]["title"],
        contract["vendor_offer"]["listing"]["item"]["image_hashes"][0])
Пример #18
0
def run(*args):
    TESTNET = args[0]
    LOGLEVEL = args[1]
    PORT = args[2]
    ALLOWIP = args[3]
    SSL = args[4]
    RESTPORT = args[5]
    WSPORT = args[6]

    # database
    db = Database(TESTNET)

    # key generation
    keys = KeyChain(db)

    # logging
    logFile = logfile.LogFile.fromFullPath(DATA_FOLDER + "debug.log", rotateLength=15000000, maxRotatedFiles=1)
    log.addObserver(FileLogObserver(logFile, level=LOGLEVEL).emit)
    log.addObserver(FileLogObserver(level=LOGLEVEL).emit)
    logger = Logger(system="OpenBazaard")

    # NAT traversal
    p = PortMapper()
    threading.Thread(target=p.add_port_mapping, args=(PORT, PORT, "UDP")).start()
    logger.info("Finding NAT Type...")
    while True:
        # sometimes the stun server returns a code the client
        # doesn't understand so we have to try again
        try:
            response = stun.get_ip_info(source_port=PORT)
            break
        except Exception:
            pass
    logger.info("%s on %s:%s" % (response[0], response[1], response[2]))
    nat_type = response[0]
    ip_address = response[1]
    port = response[2]

    # TODO: use TURN if symmetric NAT

    def on_bootstrap_complete(resp):
        logger.info("bootstrap complete")
        mserver.get_messages(mlistener)
        task.LoopingCall(check_unfunded_for_payment, db, libbitcoin_client, nlistener, TESTNET).start(600)

    protocol = OpenBazaarProtocol((ip_address, port), response[0], testnet=TESTNET)

    # kademlia
    node = Node(keys.guid, ip_address, port, signed_pubkey=keys.guid_signed_pubkey, vendor=Profile(db).get().vendor)

    storage = ForgetfulStorage() if TESTNET else PersistentStorage(db.DATABASE)

    try:
        kserver = Server.loadState(DATA_FOLDER + 'cache.pickle', ip_address, port, protocol, db,
                                   on_bootstrap_complete, storage=storage)
    except Exception:
        kserver = Server(node, db, KSIZE, ALPHA, storage=storage)
        kserver.protocol.connect_multiplexer(protocol)
        kserver.bootstrap(kserver.querySeed(SEED)).addCallback(on_bootstrap_complete)
    kserver.saveStateRegularly(DATA_FOLDER + 'cache.pickle', 10)
    protocol.register_processor(kserver.protocol)

    if nat_type != "Full Cone":
        kserver.protocol.ping(SEED_NODE_TESTNET if TESTNET else SEED_NODE)

    # market
    mserver = network.Server(kserver, keys.signing_key, db)
    mserver.protocol.connect_multiplexer(protocol)
    protocol.register_processor(mserver.protocol)

    reactor.listenUDP(port, protocol)

    class OnlyIP(Site):
        def __init__(self, resource, ip, timeout=60 * 60 * 1):
            self.ip = ip
            Site.__init__(self, resource, timeout=timeout)

        def buildProtocol(self, addr):
            if addr.host == self.ip:
                return Site.buildProtocol(self, addr)
            return None

    # websockets api
    if SSL:
        ws_factory = WSFactory("wss://127.0.0.1:" + str(WSPORT), mserver, kserver, only_ip=ALLOWIP)
        contextFactory = ChainedOpenSSLContextFactory(SSL_KEY, SSL_CERT)
        ws_factory.protocol = WSProtocol
        listenWS(ws_factory, contextFactory)
    else:
        ws_factory = WSFactory("ws://127.0.0.1:" + str(WSPORT), mserver, kserver, only_ip=ALLOWIP)
        ws_factory.protocol = WSProtocol
        listenWS(ws_factory)

    if ALLOWIP != "127.0.0.1" and ALLOWIP != "0.0.0.0":
        ws_interface = "0.0.0.0"
    else:
        ws_interface = ALLOWIP
    webdir = File(".")
    web = Site(webdir)

    reactor.listenTCP(WSPORT - 1, web, interface=ws_interface)

    # rest api
    api = OpenBazaarAPI(mserver, kserver, protocol)
    if ALLOWIP != "127.0.0.1" and ALLOWIP != "0.0.0.0":
        rest_interface = "0.0.0.0"
        site = OnlyIP(api, ALLOWIP, timeout=None)
    else:
        rest_interface = ALLOWIP
        site = Site(api, timeout=None)
    if SSL:
        reactor.listenSSL(RESTPORT, site, ChainedOpenSSLContextFactory(SSL_KEY, SSL_CERT), interface=rest_interface)
    else:
        reactor.listenTCP(RESTPORT, site, interface=rest_interface)

    # blockchain
    if TESTNET:
        libbitcoin_client = LibbitcoinClient(LIBBITCOIN_SERVER_TESTNET, log=Logger(service="LibbitcoinClient"))
    else:
        libbitcoin_client = LibbitcoinClient(LIBBITCOIN_SERVER, log=Logger(service="LibbitcoinClient"))

    # listeners
    nlistener = NotificationListenerImpl(ws_factory, db)
    mserver.protocol.add_listener(nlistener)
    mlistener = MessageListenerImpl(ws_factory, db)
    mserver.protocol.add_listener(mlistener)
    blistener = BroadcastListenerImpl(ws_factory, db)
    mserver.protocol.add_listener(blistener)

    protocol.set_servers(ws_factory, libbitcoin_client)

    logger.info("Startup took %s seconds" % str(round(time.time() - args[7], 2)))

    reactor.run()
Пример #19
0
    def open_dispute(self, order_id, claim):
        """
        Given and order ID we will pull the contract from disk and send it along with the claim
        to both the moderator and other party to the dispute. If either party isn't online we will stick
        it in the DHT for them.
        """
        try:
            file_path = DATA_FOLDER + "purchases/in progress" + order_id + ".json"
            with open(file_path, 'r') as filename:
                contract = json.load(filename, object_pairs_hook=OrderedDict)
                guid = contract["vendor_offer"]["listing"]["id"]["guid"]
                enc_key = contract["vendor_offer"]["listing"]["id"]["pubkeys"]["encryption"]
                proof_sig = self.db.Purchases().get_proof_sig(order_id)
        except Exception:
            try:
                file_path = DATA_FOLDER + "sales/in progress/" + order_id + ".json"
                with open(file_path, 'r') as filename:
                    contract = json.load(filename, object_pairs_hook=OrderedDict)
                    guid = contract["buyer_order"]["order"]["id"]["guid"]
                    enc_key = contract["buyer_order"]["order"]["id"]["pubkeys"]["encryption"]
                    proof_sig = None
            except Exception:
                return False
        keychain = KeyChain(self.db)
        contract["dispute"] = {}
        contract["dispute"]["info"] = {}
        contract["dispute"]["info"]["claim"] = claim
        contract["dispute"]["info"]["guid"] = keychain.guid.encode("hex")
        contract["dispute"]["info"]["avatar_hash"] = Profile(self.db).get().avatar_hash.encode("hex")
        if proof_sig:
            contract["dispute"]["info"]["proof_sig"] = base64.b64encode(proof_sig)
        info = json.dumps(contract["dispute"]["info"], indent=4)
        contract["dispute"]["signature"] = base64.b64encode(keychain.signing_key.sign(info)[:64])
        mod_guid = contract["buyer_order"]["order"]["moderator"]
        for mod in contract["vendor_offer"]["listing"]["moderators"]:
            if mod["guid"] == mod_guid:
                mod_enc_key = mod["pubkeys"]["encryption"]["key"]

        def get_node(node_to_ask, recipient_guid, public_key):
            def parse_response(response):
                if not response[0]:
                    self.send_message(Node(unhexlify(recipient_guid)),
                                      public_key,
                                      objects.PlaintextMessage.Type.Value("DISPUTE_OPEN"),
                                      contract,
                                      order_id,
                                      store_only=True)

            if node_to_ask:
                skephem = PrivateKey.generate()
                pkephem = skephem.public_key.encode(nacl.encoding.RawEncoder)
                box = Box(skephem, PublicKey(public_key, nacl.encoding.HexEncoder))
                nonce = nacl.utils.random(Box.NONCE_SIZE)
                ciphertext = box.encrypt(json.dumps(contract, indent=4), nonce)
                d = self.protocol.callDisputeOpen(node_to_ask, pkephem, ciphertext)
                return d.addCallback(parse_response)
            else:
                return parse_response([False])

        self.kserver.resolve(unhexlify(guid)).addCallback(get_node, guid, enc_key)
        self.kserver.resolve(unhexlify(mod_guid)).addCallback(get_node, mod_guid, mod_enc_key)
Пример #20
0
            def history_fetched(ec, history):
                outpoints = []
                satoshis = 0
                outputs = []
                dispute_json = {"dispute_resolution": {"resolution": {}}}
                if ec:
                    print ec
                else:
                    for tx_type, txid, i, height, value in history:  # pylint: disable=W0612
                        if tx_type == obelisk.PointIdent.Output:
                            satoshis += value
                            outpoint = txid.encode("hex") + ":" + str(i)
                            if outpoint not in outpoints:
                                outpoints.append(outpoint)

                    satoshis -= TRANSACTION_FEE
                    moderator_fee = round(float(moderator_percentage * satoshis))
                    satoshis -= moderator_fee

                    outputs.append({'value': moderator_fee, 'address': moderator_address})
                    dispute_json["dispute_resolution"]["resolution"]["moderator_address"] = moderator_address
                    dispute_json["dispute_resolution"]["resolution"]["moderator_fee"] = moderator_fee
                    dispute_json["dispute_resolution"]["resolution"]["transaction_fee"] = TRANSACTION_FEE
                    if float(buyer_percentage) > 0:
                        amt = round(float(buyer_percentage * satoshis))
                        dispute_json["dispute_resolution"]["resolution"]["buyer_payout"] = amt
                        outputs.append({'value': amt,
                                        'address': buyer_address})
                    if float(vendor_percentage) > 0:
                        amt = round(float(vendor_percentage * satoshis))
                        dispute_json["dispute_resolution"]["resolution"]["vendor_payout"] = amt
                        outputs.append({'value': amt,
                                        'address': vendor_address})
                    tx = bitcoin.mktx(outpoints, outputs)
                    chaincode = contract["buyer_order"]["order"]["payment"]["chaincode"]
                    redeem_script = str(contract["buyer_order"]["order"]["payment"]["redeem_script"])
                    masterkey_m = bitcoin.bip32_extract_key(KeyChain(self.db).bitcoin_master_privkey)
                    moderator_priv = derive_childkey(masterkey_m, chaincode, bitcoin.MAINNET_PRIVATE)
                    signatures = []
                    for index in range(0, len(outpoints)):
                        sig = bitcoin.multisign(tx, index, redeem_script, moderator_priv)
                        signatures.append({"input_index": index, "signature": sig})
                    dispute_json["dispute_resolution"]["resolution"]["order_id"] = order_id
                    dispute_json["dispute_resolution"]["resolution"]["tx_signatures"] = signatures
                    dispute_json["dispute_resolution"]["resolution"]["claim"] = self.db.Cases().get_claim(order_id)
                    dispute_json["dispute_resolution"]["resolution"]["decision"] = resolution
                    dispute_json["dispute_resolution"]["signature"] = \
                        base64.b64encode(KeyChain(self.db).signing_key.sign(json.dumps(
                            dispute_json["dispute_resolution"]["resolution"]))[:64])

                    def get_node(node_to_ask, recipient_guid, public_key):
                        def parse_response(response):
                            if not response[0]:
                                self.send_message(Node(unhexlify(recipient_guid)),
                                                  public_key,
                                                  objects.PlaintextMessage.Type.Value("DISPUTE_CLOSE"),
                                                  dispute_json,
                                                  order_id,
                                                  store_only=True)

                        if node_to_ask:
                            skephem = PrivateKey.generate()
                            pkephem = skephem.public_key.encode(nacl.encoding.RawEncoder)
                            box = Box(skephem, PublicKey(public_key, nacl.encoding.HexEncoder))
                            nonce = nacl.utils.random(Box.NONCE_SIZE)
                            ciphertext = box.encrypt(json.dumps(dispute_json, indent=4), nonce)
                            d = self.protocol.callDisputeClose(node_to_ask, pkephem, ciphertext)
                            return d.addCallback(parse_response)
                        else:
                            return parse_response([False])

                    self.kserver.resolve(unhexlify(vendor_guid)).addCallback(get_node, vendor_guid, vendor_enc_key)
                    self.kserver.resolve(unhexlify(buyer_guid)).addCallback(get_node, buyer_guid, buyer_enc_key)
                    self.db.Cases().update_status(order_id, 1)
Пример #21
0
    def create(self,
               expiration_date,
               metadata_category,
               title,
               description,
               currency_code,
               price,
               process_time,
               nsfw,
               shipping_origin,
               shipping_regions,
               est_delivery_domestic=None,
               est_delivery_international=None,
               keywords=None,
               category=None,
               condition=None,
               sku=None,
               images=None,
               free_shipping=None,
               shipping_currency_code=None,
               shipping_domestic=None,
               shipping_international=None):
        """
        All parameters are strings except:

        :param expiration_date: `string` (must be formatted UTC datetime)
        :param keywords: `list`
        :param nsfw: `boolean`
        :param images: a `list` of image files
        :param free_shipping: `boolean`
        :param shipping_origin: a 'string' formatted `CountryCode`
        :param shipping_regions: a 'list' of 'string' formatted `CountryCode`s
        """

        # TODO: import keys into the contract, import moderator information from db, sign contract.
        profile = Profile().get()
        keychain = KeyChain()
        self.contract = OrderedDict({
            "vendor_offer": {
                "listing": {
                    "metadata": {
                        "version": "0.1",
                        "expiry": expiration_date + " UTC",
                        "category": metadata_category,
                        "category_sub": "fixed price"
                    },
                    "id": {
                        "guid": keychain.guid.encode("hex"),
                        "pubkeys": {
                            "guid":
                            keychain.guid_signed_pubkey[64:].encode("hex"),
                            "bitcoin": keychain.bitcoin_master_pubkey
                        }
                    },
                    "item": {
                        "title": title,
                        "description": description,
                        "process_time": process_time,
                        "price_per_unit": {},
                        "nsfw": nsfw
                    }
                }
            }
        })
        if metadata_category == "physical good" and condition is not None:
            self.contract["vendor_offer"]["listing"]["item"][
                "condition"] = condition
        if currency_code.upper() == "BTC":
            item = self.contract["vendor_offer"]["listing"]["item"]
            item["price_per_unit"]["bitcoin"] = price
        else:
            item = self.contract["vendor_offer"]["listing"]["item"]
            item["price_per_unit"]["fiat"] = {}
            item["price_per_unit"]["fiat"]["price"] = price
            item["price_per_unit"]["fiat"]["currency_code"] = currency_code
        if keywords is not None:
            self.contract["vendor_offer"]["listing"]["item"]["keywords"] = []
            self.contract["vendor_offer"]["listing"]["item"][
                "keywords"].extend(keywords)
        if category is not None:
            self.contract["vendor_offer"]["listing"]["item"][
                "category"] = category
        if sku is not None:
            self.contract["vendor_offer"]["listing"]["item"]["sku"] = sku
        if metadata_category == "physical good":
            self.contract["vendor_offer"]["listing"]["shipping"] = {}
            shipping = self.contract["vendor_offer"]["listing"]["shipping"]
            shipping["shipping_origin"] = shipping_origin
            if free_shipping is False:
                self.contract["vendor_offer"]["listing"]["shipping"][
                    "free"] = False
                self.contract["vendor_offer"]["listing"]["shipping"][
                    "flat_fee"] = {}
                if shipping_currency_code == "BTC":
                    self.contract["vendor_offer"]["listing"]["shipping"][
                        "flat_fee"]["bitcoin"] = {}
                    self.contract["vendor_offer"]["listing"]["shipping"][
                        "flat_fee"]["bitcoin"]["domestic"] = shipping_domestic
                    self.contract["vendor_offer"]["listing"]["shipping"][
                        "flat_fee"]["bitcoin"][
                            "international"] = shipping_international
                else:
                    shipping = self.contract["vendor_offer"]["listing"][
                        "shipping"]
                    shipping["flat_fee"]["fiat"] = {}
                    shipping["flat_fee"]["fiat"]["price"] = {}
                    shipping["flat_fee"]["fiat"]["price"][
                        "domestic"] = shipping_domestic
                    shipping["flat_fee"]["fiat"]["price"][
                        "international"] = shipping_international
                    shipping["flat_fee"]["fiat"][
                        "currency_code"] = shipping_currency_code
            else:
                self.contract["vendor_offer"]["listing"]["shipping"][
                    "free"] = True
            self.contract["vendor_offer"]["listing"]["shipping"][
                "shipping_regions"] = []
            for region in shipping_regions:
                shipping = self.contract["vendor_offer"]["listing"]["shipping"]
                shipping["shipping_regions"].append(region)
            listing = self.contract["vendor_offer"]["listing"]
            listing["shipping"]["est_delivery"] = {}
            listing["shipping"]["est_delivery"][
                "domestic"] = est_delivery_domestic
            listing["shipping"]["est_delivery"][
                "international"] = est_delivery_international
        if profile.HasField("handle"):
            self.contract["vendor_offer"]["listing"]["id"][
                "blockchain_id"] = profile.handle
        if images is not None:
            self.contract["vendor_offer"]["listing"]["item"][
                "image_hashes"] = []
            for image in images:
                hash_value = digest(image).encode("hex")
                self.contract["vendor_offer"]["listing"]["item"][
                    "image_hashes"].append(hash_value)
                with open(DATA_FOLDER + "store/media/" + hash_value,
                          'w') as outfile:
                    outfile.write(image)
                HashMap().insert(digest(image),
                                 DATA_FOLDER + "store/media/" + hash_value)

        listing = json.dumps(self.contract["vendor_offer"]["listing"],
                             indent=4)
        self.contract["vendor_offer"]["signature"] = \
            keychain.signing_key.sign(listing, encoder=nacl.encoding.HexEncoder)[:128]
        self.save()
Пример #22
0
def run(*args):
    TESTNET = args[0]

    # Create the database
    db = Database(testnet=TESTNET)

    # logging
    logFile = logfile.LogFile.fromFullPath(DATA_FOLDER + "debug.log",
                                           rotateLength=15000000,
                                           maxRotatedFiles=1)
    log.addObserver(FileLogObserver(logFile, level="debug").emit)
    log.addObserver(FileLogObserver(level="debug").emit)
    logger = Logger(system="Httpseed")

    # Load the keys
    keychain = KeyChain(db)

    if os.path.isfile(DATA_FOLDER + 'keys.pickle'):
        keys = pickle.load(open(DATA_FOLDER + "keys.pickle", "r"))
        signing_key_hex = keys["signing_privkey"]
        signing_key = nacl.signing.SigningKey(signing_key_hex,
                                              encoder=nacl.encoding.HexEncoder)
    else:
        signing_key = nacl.signing.SigningKey.generate()
        keys = {
            'signing_privkey':
            signing_key.encode(encoder=nacl.encoding.HexEncoder),
            'signing_pubkey':
            signing_key.verify_key.encode(encoder=nacl.encoding.HexEncoder)
        }
        pickle.dump(keys, open(DATA_FOLDER + "keys.pickle", "wb"))

    # Stun
    port = 18467 if not TESTNET else 28467
    logger.info("Finding NAT Type...")
    response = stun.get_ip_info(stun_host="stun.l.google.com",
                                source_port=port,
                                stun_port=19302)
    logger.info("%s on %s:%s" % (response[0], response[1], response[2]))
    ip_address = response[1]
    port = response[2]

    # Start the kademlia server
    this_node = Node(keychain.guid,
                     ip_address,
                     port,
                     keychain.guid_signed_pubkey,
                     vendor=False)
    protocol = OpenBazaarProtocol((ip_address, port),
                                  response[0],
                                  testnet=TESTNET)

    try:
        kserver = Server.loadState('cache.pickle', ip_address, port, protocol,
                                   db)
    except Exception:
        kserver = Server(this_node, db)
        kserver.protocol.connect_multiplexer(protocol)

    protocol.register_processor(kserver.protocol)
    kserver.saveStateRegularly('cache.pickle', 10)

    # start the market server
    mserver = network.Server(kserver, keychain.signing_key, db)
    mserver.protocol.connect_multiplexer(protocol)
    protocol.register_processor(mserver.protocol)

    reactor.listenUDP(port, protocol)

    class WebResource(resource.Resource):
        def __init__(self, kserver_r):
            resource.Resource.__init__(self)
            self.kserver = kserver_r
            self.nodes = {}
            for bucket in self.kserver.protocol.router.buckets:
                for node in bucket.getNodes():
                    self.nodes[(node.ip, node.port)] = node
            self.nodes[(this_node.ip, this_node.port)] = this_node
            loopingCall = task.LoopingCall(self.crawl)
            loopingCall.start(180, True)

        def crawl(self):
            def gather_results(result):
                for proto in result:
                    n = objects.Node()
                    try:
                        n.ParseFromString(proto)
                        node = Node(n.guid, n.ip, n.port, n.signedPublicKey,
                                    n.vendor)
                        self.nodes[(node.ip, node.port)] = node
                    except Exception:
                        pass

            def start_crawl(results):
                for node, result in results.items():
                    if not result[0]:
                        del self.nodes[(node.ip, node.port)]
                node = Node(digest(random.getrandbits(255)))
                nearest = self.kserver.protocol.router.findNeighbors(node)
                spider = NodeSpiderCrawl(self.kserver.protocol, node, nearest,
                                         100, 4)
                spider.find().addCallback(gather_results)

            ds = {}
            for bucket in self.kserver.protocol.router.buckets:
                for node in bucket.getNodes():
                    self.nodes[(node.ip, node.port)] = node
            for node in self.nodes.values():
                if node.id != this_node.id:
                    ds[node] = self.kserver.protocol.callPing(node)
            deferredDict(ds).addCallback(start_crawl)

        def getChild(self, child, request):
            return self

        def render_GET(self, request):
            nodes = self.nodes.values()
            shuffle(nodes)
            logger.info("Received a request for nodes, responding...")
            if "format" in request.args:
                if request.args["format"][0] == "json":
                    json_list = []
                    if "type" in request.args and request.args["type"][
                            0] == "vendors":
                        for node in nodes:
                            if node.vendor is True:
                                node_dic = {}
                                node_dic["ip"] = node.ip
                                node_dic["port"] = node.port
                                node_dic["guid"] = node.id.encode("hex")
                                node_dic[
                                    "signed_pubkey"] = node.signed_pubkey.encode(
                                        "hex")
                                json_list.append(node_dic)
                        sig = signing_key.sign(str(json_list))
                        resp = {
                            "peers": json_list,
                            "signature": hexlify(sig[:64])
                        }
                        request.write(json.dumps(resp, indent=4))
                    else:
                        for node in nodes[:50]:
                            node_dic = {}
                            node_dic["ip"] = node.ip
                            node_dic["port"] = node.port
                            json_list.append(node_dic)
                        sig = signing_key.sign(str(json_list))
                        resp = {
                            "peers": json_list,
                            "signature": hexlify(sig[:64])
                        }
                        request.write(json.dumps(resp, indent=4))
                elif request.args["format"][0] == "protobuf":
                    proto = peers.PeerSeeds()
                    for node in nodes[:50]:
                        peer = peers.PeerData()
                        peer.ip_address = node.ip
                        peer.port = node.port
                        peer.vendor = node.vendor
                        proto.peer_data.append(peer.SerializeToString())

                    sig = signing_key.sign("".join(proto.peer_data))[:64]
                    proto.signature = sig
                    uncompressed_data = proto.SerializeToString()
                    request.write(uncompressed_data.encode("zlib"))
            else:
                proto = peers.PeerSeeds()
                if "type" in request.args and request.args["type"][
                        0] == "vendors":
                    for node in nodes:
                        if node.vendor is True:
                            peer = peers.PeerData()
                            peer.ip_address = node.ip
                            peer.port = node.port
                            peer.vendor = node.vendor
                            peer.guid = node.id
                            peer.signedPubkey = node.signed_pubkey
                            proto.peer_data.append(peer.SerializeToString())

                    sig = signing_key.sign("".join(proto.peer_data))[:64]
                    proto.signature = sig
                    uncompressed_data = proto.SerializeToString()
                    request.write(uncompressed_data.encode("zlib"))
                else:
                    for node in nodes[:50]:
                        peer = peers.PeerData()
                        peer.ip_address = node.ip
                        peer.port = node.port
                        peer.vendor = node.vendor
                        proto.peer_data.append(peer.SerializeToString())

                    sig = signing_key.sign("".join(proto.peer_data))[:64]
                    proto.signature = sig
                    uncompressed_data = proto.SerializeToString()
                    request.write(uncompressed_data.encode("zlib"))
            request.finish()
            return server.NOT_DONE_YET

    server_protocol = server.Site(WebResource(kserver))
    reactor.listenTCP(8080, server_protocol)

    reactor.run()
Пример #23
0
def run(*args):
    TESTNET = args[0]

    # database
    db = Database(TESTNET)

    # key generation
    keys = KeyChain(db)

    # logging
    # TODO: prune this log file and prevent it from getting too large?
    logFile = logfile.LogFile.fromFullPath(DATA_FOLDER + "debug.log")
    log.addObserver(log.FileLogObserver(logFile).emit)
    log.startLogging(sys.stdout)

    # stun
    # TODO: accept port from command line
    port = 18467 if not TESTNET else 28467
    print "Finding NAT Type.."
    # TODO: maintain a list of backup STUN servers and try them if ours fails
    response = stun.get_ip_info(stun_host="seed.openbazaar.org",
                                source_port=port)
    print "%s on %s:%s" % (response[0], response[1], response[2])
    ip_address = response[1]
    port = response[2]

    # TODO: try UPnP if restricted NAT

    # TODO: maintain open connection to seed node if STUN/UPnP fail

    # TODO: use TURN if symmetric NAT

    def on_bootstrap_complete(resp):
        mlistener = MessageListenerImpl(ws_factory, db)
        mserver.get_messages(mlistener)
        mserver.protocol.add_listener(mlistener)
        nlistener = NotificationListenerImpl(ws_factory, db)
        mserver.protocol.add_listener(nlistener)

        # TODO: after bootstrap run through any pending contracts and see if the bitcoin address
        # has been funded, if not listen on the address and start the 10 minute delete timer.

    protocol = OpenBazaarProtocol((ip_address, port), testnet=TESTNET)

    # kademlia
    node = Node(keys.guid,
                ip_address,
                port,
                signed_pubkey=keys.guid_signed_pubkey)

    try:
        kserver = Server.loadState(DATA_FOLDER + 'cache.pickle',
                                   ip_address,
                                   port,
                                   protocol,
                                   db,
                                   on_bootstrap_complete,
                                   storage=PersistentStorage(db.DATABASE))
    except Exception:
        kserver = Server(node,
                         db,
                         KSIZE,
                         ALPHA,
                         storage=PersistentStorage(db.DATABASE))
        kserver.protocol.connect_multiplexer(protocol)
        kserver.bootstrap(
            kserver.querySeed("seed.openbazaar.org:8080",
                              "ddd862778e3ed71af06db0e3619a4c6269ec7468c745132dbb73982b319fc572"))\
            .addCallback(on_bootstrap_complete)
        # TODO: load seeds from config file
    kserver.saveStateRegularly(DATA_FOLDER + 'cache.pickle', 10)
    protocol.register_processor(kserver.protocol)

    # market
    mserver = network.Server(kserver, keys.signing_key, db)
    mserver.protocol.connect_multiplexer(protocol)
    protocol.register_processor(mserver.protocol)

    reactor.listenUDP(port, protocol)

    # websockets api
    ws_factory = WSFactory("ws://127.0.0.1:18466", mserver, kserver)
    ws_factory.protocol = WSProtocol
    ws_factory.setProtocolOptions(allowHixie76=True)
    listenWS(ws_factory)
    webdir = File(".")
    web = Site(webdir)
    reactor.listenTCP(9000, web, interface="127.0.0.1")

    # rest api
    api = OpenBazaarAPI(mserver, kserver, protocol)
    site = Site(api, timeout=None)
    reactor.listenTCP(18469, site, interface="127.0.0.1")

    # TODO: add optional SSL on rest and websocket servers

    # blockchain
    # TODO: listen on the libbitcoin heartbeat port instead fetching height
    def height_fetched(ec, height):
        # TODO: re-broadcast any unconfirmed txs in the db using height to find confirmation status
        print "Libbitcoin server online"
        try:
            timeout.cancel()
        except Exception:
            pass

    def timeout(client):
        print "Libbitcoin server offline"
        client = None

    if TESTNET:
        libbitcoin_client = LibbitcoinClient(
            "tcp://libbitcoin2.openbazaar.org:9091")
    else:
        libbitcoin_client = LibbitcoinClient(
            "tcp://libbitcoin1.openbazaar.org:9091")

    # TODO: load libbitcoin server url from config file

    libbitcoin_client.fetch_last_height(height_fetched)
    timeout = reactor.callLater(5, timeout, libbitcoin_client)

    protocol.set_servers(ws_factory, libbitcoin_client)

    reactor.run()