Example #1
0
    def decrypt(self, memo):
        """ Decrypt a memo

            :param str memo: encrypted memo message
            :returns: encrypted memo
            :rtype: str
        """
        if not memo:
            return None

        memo_wif = self.peerplays.wallet.getPrivateKeyForPublicKey(
            self.to_account["options"]["memo_key"])
        if not memo_wif:
            raise MissingKeyError("Memo key for %s missing!" %
                                  self.to_account["name"])

        # TODO: Use pubkeys of the message, not pubkeys of account!
        print(
            PrivateKey(memo_wif),
            PublicKey(self.from_account["options"]["memo_key"],
                      prefix=self.peerplays.rpc.chain_params["prefix"]),
            memo.get("nonce"), memo.get("message"))
        return PPYMemo.decode_memo(
            PrivateKey(memo_wif),
            PublicKey(self.from_account["options"]["memo_key"],
                      prefix=self.peerplays.rpc.chain_params["prefix"]),
            memo.get("nonce"), memo.get("message"))
Example #2
0
    def update_memo_key(self, key, account=None):
        """ Update an account's memo public key

            This method does **not** add any private keys to your
            wallet but merely changes the memo public key.

            :param str key: New memo public key
            :param str account: (optional) the account to allow access
                to (defaults to ``default_account``)
        """
        if not account:
            if "default_account" in config:
                account = config["default_account"]
        if not account:
            raise ValueError("You need to provide an account")

        PublicKey(key, prefix=self.rpc.chain_params["prefix"])

        account = Account(account, peerplays_instance=self)
        account["options"]["memo_key"] = key
        op = operations.Account_update(
            **{
                "fee": {
                    "amount": 0,
                    "asset_id": "1.3.0"
                },
                "account": account["id"],
                "new_options": account["options"],
                "extensions": {}
            })
        return self.finalizeOp(op, account["name"], "active")
Example #3
0
    def decrypt(self, memo):
        """ Decrypt a memo

            :param str memo: encrypted memo message
            :returns: encrypted memo
            :rtype: str
        """
        if not memo:
            return None

        # We first try to decode assuming we received the memo
        try:
            memo_wif = self.blockchain.wallet.getPrivateKeyForPublicKey(
                memo["to"])
            pubkey = memo["from"]
        except KeyNotFound:
            try:
                # if that failed, we assume that we have sent the memo
                memo_wif = self.blockchain.wallet.getPrivateKeyForPublicKey(
                    memo["from"])
                pubkey = memo["to"]
            except KeyNotFound:
                # if all fails, raise exception
                raise MissingKeyError(
                    "Non of the required memo keys are installed!"
                    "Need any of {}".format([memo["to"], memo["from"]]))

        if not hasattr(self, 'chain_prefix'):
            self.chain_prefix = self.blockchain.prefix

        return PPYMemo.decode_memo(PrivateKey(memo_wif),
                                   PublicKey(pubkey, prefix=self.chain_prefix),
                                   memo.get("nonce"), memo.get("message"))
Example #4
0
    def encrypt(self, memo):
        """ Encrypt a memo

            :param str memo: clear text memo message
            :returns: encrypted memo
            :rtype: str
        """
        if not memo:
            return None

        nonce = str(random.getrandbits(64))
        memo_wif = self.blockchain.wallet.getPrivateKeyForPublicKey(
            self.from_account["options"]["memo_key"])
        if not memo_wif:
            raise MissingKeyError("Memo key for %s missing!" %
                                  self.from_account["name"])

        if not hasattr(self, 'chain_prefix'):
            self.chain_prefix = self.blockchain.prefix

        enc = PPYMemo.encode_memo(
            PrivateKey(memo_wif),
            PublicKey(self.to_account["options"]["memo_key"],
                      prefix=self.chain_prefix), nonce, memo)

        return {
            "message": enc,
            "nonce": nonce,
            "from": self.from_account["options"]["memo_key"],
            "to": self.to_account["options"]["memo_key"]
        }
Example #5
0
    def claim(self, account=None, **kwargs):
        """ Claim a balance from the genesis block

            :param str balance_id: The identifier that identifies the balance
                to claim (1.15.x)
            :param str account: (optional) the account that owns the bet
                (defaults to ``default_account``)
        """
        from peerplaysbase.account import Address, PublicKey
        if not account:
            if "default_account" in self.blockchain.config:
                account = self.blockchain.config["default_account"]
        if not account:
            raise ValueError("You need to provide an account")
        account = Account(account)
        pubkeys = self.blockchain.wallet.getPublicKeys()
        addresses = dict()
        for p in pubkeys:
            pubkey = PublicKey(p)
            addresses[str(
                Address.from_pubkey(pubkey, compressed=False,
                                    version=0))] = pubkey
            addresses[str(
                Address.from_pubkey(pubkey, compressed=True,
                                    version=0))] = pubkey
            addresses[str(
                Address.from_pubkey(pubkey, compressed=False,
                                    version=56))] = pubkey
            addresses[str(
                Address.from_pubkey(pubkey, compressed=True,
                                    version=56))] = pubkey

        if self["owner"] not in addresses.keys():
            raise MissingKeyError("Need key for address {}".format(
                self["owner"]))

        op = operations.Balance_claim(
            **{
                "fee": {
                    "amount": 0,
                    "asset_id": "1.3.0"
                },
                "deposit_to_account": account["id"],
                "balance_to_claim": self["id"],
                "balance_owner_key": addresses[self["owner"]],
                "total_claimed": self["balance"],
                "prefix": self.blockchain.prefix
            })
        signers = [
            account["name"],  # The fee payer and receiver account
            addresses.get(self["owner"])  # The genesis balance!
        ]
        return self.blockchain.finalizeOp(op, signers, "active", **kwargs)
Example #6
0
    def __init__(self, **kwargs):
        BlockchainInstance.__init__(self, **kwargs)

        pubkeys = self.blockchain.wallet.getPublicKeys()
        addresses = list()
        for p in pubkeys:
            pubkey = PublicKey(p)
            addresses.append(
                str(Address.from_pubkey(pubkey, compressed=False, version=0)))
            addresses.append(
                str(Address.from_pubkey(pubkey, compressed=True, version=0)))
            addresses.append(
                str(Address.from_pubkey(pubkey, compressed=False, version=56)))
            addresses.append(
                str(Address.from_pubkey(pubkey, compressed=True, version=56)))

        balancess = self.blockchain.rpc.get_balance_objects(addresses)

        super(GenesisBalances, self).__init__([
            GenesisBalance(x, **kwargs, blockchain_instance=self.blockchain)
            for x in balancess
        ])
Example #7
0
    def verify(self, **kwargs):
        """ Verify a message with an account's memo key

            :param str account: (optional) the account that owns the bet
                (defaults to ``default_account``)

            :returns: True if the message is verified successfully
            :raises InvalidMessageSignature if the signature is not ok
        """
        # Split message into its parts
        parts = re.split("|".join(MESSAGE_SPLIT), self.message)
        parts = [x for x in parts if x.strip()]

        assert len(parts) > 2, "Incorrect number of message parts"

        # Strip away all whitespaces before and after the message
        message = parts[0].strip()
        signature = parts[2].strip()
        # Parse the meta data
        meta = dict(re.findall(r'(\S+)=(.*)', parts[1]))

        log.info("Message is: {}".format(message))
        log.info("Meta is: {}".format(json.dumps(meta)))
        log.info("Signature is: {}".format(signature))

        # Ensure we have all the data in meta
        assert "account" in meta, "No 'account' could be found in meta data"
        assert "memokey" in meta, "No 'memokey' could be found in meta data"
        assert "block" in meta, "No 'block' could be found in meta data"
        assert "timestamp" in meta, \
            "No 'timestamp' could be found in meta data"

        account_name = meta.get("account").strip()
        memo_key = meta["memokey"].strip()

        try:
            PublicKey(memo_key, prefix=self.blockchain.prefix)
        except Exception:
            raise InvalidMemoKeyException(
                "The memo key in the message is invalid")

        # Load account from blockchain
        try:
            account = Account(account_name,
                              blockchain_instance=self.blockchain)
        except AccountDoesNotExistsException:
            raise AccountDoesNotExistsException(
                "Could not find account {}. Are you connected to the right chain?"
                .format(account_name))

        # Test if memo key is the same as on the blockchain
        if not account["options"]["memo_key"] == memo_key:
            raise WrongMemoKey(
                "Memo Key of account {} on the Blockchain".format(
                    account["name"]) +
                "differs from memo key in the message: {} != {}".format(
                    account["options"]["memo_key"], memo_key))

        # Reformat message
        enc_message = SIGNED_MESSAGE_META.format(**locals())

        # Verify Signature
        pubkey = verify_message(enc_message, unhexlify(signature))

        # Verify pubky
        pk = PublicKey(hexlify(pubkey).decode("ascii"))
        if format(pk, self.blockchain.prefix) != memo_key:
            raise InvalidMessageSignature

        return True
Example #8
0
 def test_shared_secret(self):
     for s in test_shared_secrets:
         priv = PrivateKey(s[0])
         pub = PublicKey(s[1], prefix="GPH")
         shared_secret = get_shared_secret(priv, pub)
         self.assertEqual(s[2], shared_secret)
Example #9
0
 def test_encrypt(self):
     for memo in test_cases:
         enc = encode_memo(PrivateKey(memo["wif"]),
                           PublicKey(memo["to"], prefix="GPH"),
                           memo["nonce"], memo["plain"])
         self.assertEqual(memo["message"], enc)
Example #10
0
    def disallow(self,
                 foreign,
                 permission="active",
                 account=None,
                 threshold=None):
        """ Remove additional access to an account by some other public
            key or account.

            :param str foreign: The foreign account that will obtain access
            :param str permission: (optional) The actual permission to
                modify (defaults to ``active``)
            :param str account: (optional) the account to allow access
                to (defaults to ``default_account``)
            :param int threshold: The threshold that needs to be reached
                by signatures to be able to interact
        """
        if not account:
            if "default_account" in config:
                account = config["default_account"]
        if not account:
            raise ValueError("You need to provide an account")

        if permission not in ["owner", "active"]:
            raise ValueError(
                "Permission needs to be either 'owner', or 'active")
        account = Account(account, peerplays_instance=self)
        authority = account[permission]

        try:
            pubkey = PublicKey(foreign, prefix=self.rpc.chain_params["prefix"])
            affected_items = list(
                filter(lambda x: x[0] == str(pubkey), authority["key_auths"]))
            authority["key_auths"] = list(
                filter(lambda x: x[0] != str(pubkey), authority["key_auths"]))
        except:
            try:
                foreign_account = Account(foreign, peerplays_instance=self)
                affected_items = list(
                    filter(lambda x: x[0] == foreign_account["id"],
                           authority["account_auths"]))
                authority["account_auths"] = list(
                    filter(lambda x: x[0] != foreign_account["id"],
                           authority["account_auths"]))
            except:
                raise ValueError(
                    "Unknown foreign account or unvalid public key")

        removed_weight = affected_items[0][1]

        # Define threshold
        if threshold:
            authority["weight_threshold"] = threshold

        # Correct threshold (at most by the amount removed from the
        # authority)
        try:
            self._test_weights_treshold(authority)
        except:
            log.critical("The account's threshold will be reduced by %d" %
                         (removed_weight))
            authority["weight_threshold"] -= removed_weight
            self._test_weights_treshold(authority)

        op = operations.Account_update(
            **{
                "fee": {
                    "amount": 0,
                    "asset_id": "1.3.0"
                },
                "account": account["id"],
                permission: authority,
                "extensions": {}
            })
        if permission == "owner":
            return self.finalizeOp(op, account["name"], "owner")
        else:
            return self.finalizeOp(op, account["name"], "active")
Example #11
0
    def allow(self,
              foreign,
              weight=None,
              permission="active",
              account=None,
              threshold=None):
        """ Give additional access to an account by some other public
            key or account.

            :param str foreign: The foreign account that will obtain access
            :param int weight: (optional) The weight to use. If not
                define, the threshold will be used. If the weight is
                smaller than the threshold, additional signatures will
                be required. (defaults to threshold)
            :param str permission: (optional) The actual permission to
                modify (defaults to ``active``)
            :param str account: (optional) the account to allow access
                to (defaults to ``default_account``)
            :param int threshold: The threshold that needs to be reached
                by signatures to be able to interact
        """
        from copy import deepcopy
        if not account:
            if "default_account" in config:
                account = config["default_account"]
        if not account:
            raise ValueError("You need to provide an account")

        if permission not in ["owner", "active"]:
            raise ValueError(
                "Permission needs to be either 'owner', or 'active")
        account = Account(account, peerplays_instance=self)

        if not weight:
            weight = account[permission]["weight_threshold"]

        authority = deepcopy(account[permission])
        try:
            pubkey = PublicKey(foreign, prefix=self.rpc.chain_params["prefix"])
            authority["key_auths"].append([str(pubkey), weight])
        except:
            try:
                foreign_account = Account(foreign, peerplays_instance=self)
                authority["account_auths"].append(
                    [foreign_account["id"], weight])
            except:
                raise ValueError(
                    "Unknown foreign account or invalid public key")
        if threshold:
            authority["weight_threshold"] = threshold
            self._test_weights_treshold(authority)

        op = operations.Account_update(
            **{
                "fee": {
                    "amount": 0,
                    "asset_id": "1.3.0"
                },
                "account": account["id"],
                permission: authority,
                "extensions": {},
                "prefix": self.rpc.chain_params["prefix"]
            })
        if permission == "owner":
            return self.finalizeOp(op, account["name"], "owner")
        else:
            return self.finalizeOp(op, account["name"], "active")
Example #12
0
    def create_account(
        self,
        account_name,
        registrar=None,
        referrer="1.2.0",
        referrer_percent=50,
        owner_key=None,
        active_key=None,
        memo_key=None,
        password=None,
        additional_owner_keys=[],
        additional_active_keys=[],
        additional_owner_accounts=[],
        additional_active_accounts=[],
        proxy_account="proxy-to-self",
        storekeys=True,
    ):
        """ Create new account on PeerPlays

            The brainkey/password can be used to recover all generated keys (see
            `peerplaysbase.account` for more details.

            By default, this call will use ``default_account`` to
            register a new name ``account_name`` with all keys being
            derived from a new brain key that will be returned. The
            corresponding keys will automatically be installed in the
            wallet.

            .. warning:: Don't call this method unless you know what
                          you are doing! Be sure to understand what this
                          method does and where to find the private keys
                          for your account.

            .. note:: Please note that this imports private keys
                      (if password is present) into the wallet by
                      default. However, it **does not import the owner
                      key** for security reasons. Do NOT expect to be
                      able to recover it from the wallet if you lose
                      your password!

            :param str account_name: (**required**) new account name
            :param str registrar: which account should pay the registration fee
                                (defaults to ``default_account``)
            :param str owner_key: Main owner key
            :param str active_key: Main active key
            :param str memo_key: Main memo_key
            :param str password: Alternatively to providing keys, one
                                 can provide a password from which the
                                 keys will be derived
            :param array additional_owner_keys:  Additional owner public keys
            :param array additional_active_keys: Additional active public keys
            :param array additional_owner_accounts: Additional owner account names
            :param array additional_active_accounts: Additional acctive account names
            :param bool storekeys: Store new keys in the wallet (default: ``True``)
            :raises AccountExistsException: if the account already exists on the blockchain

        """
        if not registrar and config["default_account"]:
            registrar = config["default_account"]
        if not registrar:
            raise ValueError(
                "Not registrar account given. Define it with " +
                "registrar=x, or set the default_account using 'peerplays'")
        if password and (owner_key or active_key or memo_key):
            raise ValueError("You cannot use 'password' AND provide keys!")

        try:
            Account(account_name, peerplays_instance=self)
            raise AccountExistsException
        except:
            pass

        referrer = Account(referrer, peerplays_instance=self)
        registrar = Account(registrar, peerplays_instance=self)

        " Generate new keys from password"
        from peerplaysbase.account import PasswordKey, PublicKey
        if password:
            active_key = PasswordKey(account_name, password, role="active")
            owner_key = PasswordKey(account_name, password, role="owner")
            memo_key = PasswordKey(account_name, password, role="memo")
            active_pubkey = active_key.get_public_key()
            owner_pubkey = owner_key.get_public_key()
            memo_pubkey = memo_key.get_public_key()
            active_privkey = active_key.get_private_key()
            # owner_privkey   = owner_key.get_private_key()
            memo_privkey = memo_key.get_private_key()
            # store private keys
            if storekeys:
                # self.wallet.addPrivateKey(owner_privkey)
                self.wallet.addPrivateKey(active_privkey)
                self.wallet.addPrivateKey(memo_privkey)
        elif (owner_key and active_key and memo_key):
            active_pubkey = PublicKey(active_key,
                                      prefix=self.rpc.chain_params["prefix"])
            owner_pubkey = PublicKey(owner_key,
                                     prefix=self.rpc.chain_params["prefix"])
            memo_pubkey = PublicKey(memo_key,
                                    prefix=self.rpc.chain_params["prefix"])
        else:
            raise ValueError(
                "Call incomplete! Provide either a password or public keys!")
        owner = format(owner_pubkey, self.rpc.chain_params["prefix"])
        active = format(active_pubkey, self.rpc.chain_params["prefix"])
        memo = format(memo_pubkey, self.rpc.chain_params["prefix"])

        owner_key_authority = [[owner, 1]]
        active_key_authority = [[active, 1]]
        owner_accounts_authority = []
        active_accounts_authority = []

        # additional authorities
        for k in additional_owner_keys:
            owner_key_authority.append([k, 1])
        for k in additional_active_keys:
            active_key_authority.append([k, 1])

        for k in additional_owner_accounts:
            addaccount = Account(k, peerplays_instance=self)
            owner_accounts_authority.append([addaccount["id"], 1])
        for k in additional_active_accounts:
            addaccount = Account(k, peerplays_instance=self)
            active_accounts_authority.append([addaccount["id"], 1])

        # voting account
        voting_account = Account(proxy_account or "proxy-to-self")

        op = {
            "fee": {
                "amount": 0,
                "asset_id": "1.3.0"
            },
            "registrar": registrar["id"],
            "referrer": referrer["id"],
            "referrer_percent": referrer_percent * 100,
            "name": account_name,
            'owner': {
                'account_auths': owner_accounts_authority,
                'key_auths': owner_key_authority,
                "address_auths": [],
                'weight_threshold': 1
            },
            'active': {
                'account_auths': active_accounts_authority,
                'key_auths': active_key_authority,
                "address_auths": [],
                'weight_threshold': 1
            },
            "options": {
                "memo_key": memo,
                "voting_account": voting_account["id"],
                "num_witness": 0,
                "num_committee": 0,
                "votes": [],
                "extensions": []
            },
            "extensions": {},
            "prefix": self.rpc.chain_params["prefix"]
        }
        op = operations.Account_create(**op)
        return self.finalizeOp(op, registrar, "active")