def test_MarketSmtp_send_enabled_success(self, mock_smtp): '''Email sent when enabled''' instance = mock_smtp.return_value s = SMTPNotification(self.db) s.send('test_subject', 'test_body') mock_smtp.assert_called_once_with('test_server') instance.login.assert_called_once_with('test_username', 'test_password') instance.sendmail.assert_called_once_with('test_sender', 'test_recipient', mock.ANY)
def test_MarketSmtp_send_throw_exception(self, mock_smtp): '''Email sent when enabled''' catcher = self.catcher mock_smtp.side_effect = Exception('Test exception thrown') s = SMTPNotification(self.db) s.send('test_subject', 'test_body') mock_smtp.assert_called_once_with('test_server') catch_exception = catcher.pop() self.assertEquals(catch_exception["message"][0], "[ERROR] Test exception thrown")
def test_MarketSmtp_send_disabled_not_sent(self, mock_smtp): '''Email not sent when disabled''' instance = mock_smtp.return_value self.db.settings.get.return_value = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', 0, 'test_server', 'test_sender', 'test_recipient', 'test_username', 'test_password'] s = SMTPNotification(self.db) s.send('test_subject', 'test_body') assert mock_smtp.call_count == 0 assert instance.login.call_count == 0 assert instance.sendmail.call_count == 0
def rpc_follow(self, sender, proto, signature): self.log.info("received follow request from %s" % sender) self.router.addContact(sender) try: verify_key = nacl.signing.VerifyKey(sender.pubkey) verify_key.verify(proto, signature) f = Followers.Follower() f.ParseFromString(proto) if f.guid != sender.id: raise Exception('GUID does not match sending node') if f.following != self.node.id: raise Exception('Following wrong node') f.signature = signature self.db.follow.set_follower(f.SerializeToString()) proto = Profile(self.db).get(False) m = Metadata() m.name = proto.name m.handle = proto.handle m.avatar_hash = proto.avatar_hash m.short_description = proto.short_description m.nsfw = proto.nsfw for listener in self.listeners: try: verifyObject(NotificationListener, listener) listener.notify(sender.id, f.metadata.handle, "follow", "", "", f.metadata.avatar_hash) except DoesNotImplement: pass # Send SMTP notification notification = SMTPNotification(self.db) notification.send( "[OpenBazaar] %s is now following you!" % f.metadata.name, "You have a new follower:<br><br>Name: %s<br>GUID: <a href=\"ob://%s\">%s</a><br>" "Handle: %s" % (f.metadata.name, f.guid.encode('hex'), f.guid.encode('hex'), f.metadata.handle)) return [ "True", m.SerializeToString(), self.signing_key.sign(m.SerializeToString())[:64] ] except Exception: self.log.warning("failed to validate follower") return ["False"]
def rpc_follow(self, sender, proto, signature): self.log.info("received follow request from %s" % sender) self.router.addContact(sender) try: verify_key = nacl.signing.VerifyKey(sender.pubkey) verify_key.verify(proto, signature) f = Followers.Follower() f.ParseFromString(proto) if f.guid != sender.id: raise Exception("GUID does not match sending node") if f.following != self.node.id: raise Exception("Following wrong node") f.signature = signature self.db.follow.set_follower(f.SerializeToString()) proto = Profile(self.db).get(False) m = Metadata() m.name = proto.name m.handle = proto.handle m.avatar_hash = proto.avatar_hash m.short_description = proto.short_description m.nsfw = proto.nsfw for listener in self.listeners: try: verifyObject(NotificationListener, listener) listener.notify(sender.id, f.metadata.handle, "follow", "", "", f.metadata.avatar_hash) except DoesNotImplement: pass # Send SMTP notification notification = SMTPNotification(self.db) notification.send( "[OpenBazaar] %s is now following you!" % f.metadata.name, 'You have a new follower:<br><br>Name: %s<br>GUID: <a href="ob://%s">%s</a><br>' "Handle: %s" % (f.metadata.name, f.guid.encode("hex"), f.guid.encode("hex"), f.metadata.handle), ) return ["True", m.SerializeToString(), self.signing_key.sign(m.SerializeToString())[:64]] except Exception: self.log.warning("failed to validate follower") return ["False"]
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 = deepcopy(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"] del tmp_contract["dispute"] 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"]) public_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 = "" proof_sig = None elif contract["dispute"]["info"]["guid"] == contract["buyer_order"]["order"]["id"]["guid"]: guid = unhexlify(contract["buyer_order"]["order"]["id"]["guid"]) public_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 = "" proof_sig = contract["dispute"]["info"]["proof_sig"] else: raise Exception("Dispute guid not in contract") verify_key = nacl.signing.VerifyKey(public_key) verify_key.verify(json.dumps(contract["dispute"]["info"], indent=4), base64.b64decode(contract["dispute"]["signature"])) p = PlaintextMessage() p.sender_guid = guid p.handle = handle p.pubkey = public_key p.subject = str(order_id) p.type = PlaintextMessage.Type.Value("DISPUTE_OPEN") p.message = str(contract["dispute"]["info"]["claim"]) p.timestamp = int(time.time()) p.avatar_hash = unhexlify(str(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.sales.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"] and \ contract["vendor_offer"]["listing"]["id"]["blockchain_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"] and \ contract["buyer_order"]["order"]["id"]["blockchain_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"], 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(os.path.join(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, "") title = contract["vendor_offer"]["listing"]["item"]["title"] notification_listener.notify(guid, handle, "dispute_open", order_id, title, unhexlify(contract["vendor_offer"]["listing"]["item"]["image_hashes"][0])) # Send SMTP notification notification = SMTPNotification(db) guid = guid.encode("hex") notification.send("[OpenBazaar] Dispute Opened", "A dispute has been opened.\n\n" "Order: %s\n" "Opened By: %s\n" "Title: %s" % (order_id, guid, title))
def close_dispute(resolution_json, db, message_listener, notification_listener, testnet): """ This function processes a dispute close message received from the moderator. It will store the resolution in the contract and send a notification to the listeners telling them that the dispute is resolved. Args: resolution_json: The `dispute_resolution` portion of the contract received from the moderator. db: a `Database` object. message_listener: a `MessageListenerImpl` object. notification_listener: a `NotificationListenerImpl` object. testnet: `bool` of whether we're on testnet or not. """ order_id = resolution_json["dispute_resolution"]["resolution"]["order_id"] if os.path.exists(os.path.join(DATA_FOLDER, "purchases", "in progress", order_id + ".json")): file_path = os.path.join(DATA_FOLDER, "purchases", "in progress", order_id + ".json") elif os.path.exists(os.path.join(DATA_FOLDER, "store", "contracts", "in progress", order_id + ".json")): file_path = os.path.join(DATA_FOLDER, "store", "contracts", "in progress", order_id + ".json") with open(file_path, 'r') as filename: contract = json.load(filename, object_pairs_hook=OrderedDict) for moderator in contract["vendor_offer"]["listing"]["moderators"]: if moderator["guid"] == contract["buyer_order"]["order"]["moderator"]: moderator_guid = unhexlify(moderator["guid"]) moderator_handle = moderator["blockchain_id"] moderator_pubkey = unhexlify(moderator["pubkeys"]["guid"]) moderator_avatar = unhexlify(moderator["avatar"]) verify_key = nacl.signing.VerifyKey(moderator_pubkey) verify_key.verify(json.dumps(resolution_json["dispute_resolution"]["resolution"], indent=4), base64.b64decode(resolution_json["dispute_resolution"]["signature"])) contract["dispute_resolution"] = resolution_json["dispute_resolution"] if db.purchases.get_purchase(order_id) is not None: db.purchases.update_status(order_id, 5) elif db.sales.get_sale(order_id) is not None: db.sales.update_status(order_id, 5) with open(file_path, 'wb') as outfile: outfile.write(json.dumps(contract, indent=4)) p = PlaintextMessage() p.sender_guid = moderator_guid p.handle = moderator_handle p.pubkey = moderator_pubkey p.subject = str(order_id) p.type = PlaintextMessage.Type.Value("DISPUTE_CLOSE") p.message = str(resolution_json["dispute_resolution"]["resolution"]["decision"]) p.timestamp = int(time.time()) p.avatar_hash = moderator_avatar message_listener.notify(p, "") title = contract["vendor_offer"]["listing"]["item"]["title"] notification_listener.notify(moderator_guid, moderator_handle, "dispute_close", order_id, title, contract["vendor_offer"]["listing"]["item"]["image_hashes"][0]) # Send SMTP notification notification = SMTPNotification(db) guid = moderator_guid.encode("hex") notification.send("[OpenBazaar] Dispute Closed", "A dispute has been closed.\n\n" "Order: %s\n" "Closed By: %s\n" "Title: %s" % (order_id, guid, title))