piWallet icon indicating copy to clipboard operation
piWallet copied to clipboard

Importing of Private Keys

Open muwaka opened this issue 7 years ago • 2 comments

Hello Johnathan,

well, this is not really an issue, but somehow i do not get how to create a pull request.

I implemented the feature, that you can import private keys to your wallet. This is kind of a quick-shot solution. Error handling and internationalization can be improved. But i saw private key handling is on your todo list, and this would be a part of it

To view/wallet.php i added the following between WALLET_SUPPORT and WALLET_2FAON, so the button is show on the top of your wallet between the support button and the enable 2FA button:

<form action="index.php" method="POST">
   <input type="hidden" name="action" value="enterprivkey" />
   <button type="submit" class="btn btn-default"><?php echo $lang['WALLET_ENTER_PRIVKEY']; ?> </button>
</form>

to index.php i added this to the switch($_POST['action']):

// this part shows an input and a button at the top of the site to insert your private keys
case "enterprivkey":
    $user = new User($mysqli);
    $enterprivkey = $user->enterPrivKey();
    echo $enterprivkey;
    break;

// this part is handling the click on the submit button from the above code
case "submitprivkey":
    if(empty($_POST['privkey'])) {
        $error['message'] = "No private keys submitted!";
        break;
    }
    $privkey = $_POST['privkey'];
 
    // check length and check for valid characters depends on your *coind implementation.
    // this would be better to be checked by the *coind daemon,
    // since it checks them also and completely skip the checks here

    // check length
    if(strlen($privkey) !== 52) {
        $error['message'] = "Length of private key is wrong: ". strval(strlen($privkey)) .". Has to be 52!";
        break;
    }
    // check for valid characters
    for($i = 0; $i < strlen($privkey); $i++) {
        // valid characters are between 0 and 9 and between a and f
        if($privkey[$i] < "0" || $privkey[$i] > "9") {
            if(strtolower($privkey[$i]) < "a" || strtolower($privkey[$i]) > "z") {
                $error['message'] = "Invalid characters are in the private key!";
                break;
            }
        }
    }
 
    $result = $client->importPrivateKey($user_session, $privkey);
    $r = json_decode($result);
    if($r->{'error'} == null) {
        $error['message'] = "Successfully added a Private Key to your wallet. It can take a while that it appears in your wallet since the network has to verify your action.";
    } else {
        $error['message'] = $r->{'error'}->{'message'};
    }
    break;

At the end of classes/Client.php i added this:

function importPrivateKey($user_session, $private_key) {
    return $this->jsonrpc->importprivkey($private_key, "zelles(" . $user_session . ")");
}

This function i added to classes/User.php

function enterPrivKey() {
    $htmlcode = '
        <form action="index.php" method="POST"method="POST" id="enterprivkeyform">
            <input type="hidden" name="action" value="submitprivkey" />
            <input type="text" name="privkey" placeholder="Private Key" />
            <button type="submit" class="btn btn-default">Submit</button>
        </form>';
        return $htmlcode;
}

The change of jsonRPCClient.php was the toughest part. Since your code always resulted in a http error 500 when sending importprivkey, i had to use php-curl to call the *coind daemon. Maybe it is better so switch completely to php-curl because the error handling is much better and options can easier be set, than with fopen. So i enhanced the function __call by the following:

public function __call($method,$params) {
    /* ... your code ... */

    // my code handling "importprivkey"
    if($method === "importprivkey") {
        $privkey = $params[0];
        $account = $params[1];
        $rescan = "true";

        $curl = curl_init();

        curl_setopt($curl, CURLOPT_URL, $this->url);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // enable return as string
        curl_setopt($curl, CURLOPT_POST, 1); // enable post
        curl_setopt($curl, CURLOPT_POSTFIELDS, '{"jsonrpc":"1.0","method":"importprivkey","params":["'.$privkey.'", "'.$account.'", true]}'); // enable post fiels
        curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type:application/json')); // set content-type

        $result = curl_exec($curl);
        return $result;
    } else {
        // your old code handling all the other methods
        if ($fp = fopen($this->url, 'r', false, $context)) {
            $response = '';
            while($row = fgets($fp)) {
                $response.= trim($row)."\n";
            }
            $this->debug && $debug.='***** Server response *****'."\n".$response.'***** End of server response *****'."\n";
            $response = json_decode($response,true);
        } else {
            throw new Exception('Unable to connect to '.$this->url);
        }
   }
   /* ... again your code ... */
}

Hope this helps, Gottfried, servus.at

muwaka avatar Jun 22 '18 09:06 muwaka

Thank you, I'll be reviewing this and will commit to master.

jfm-so avatar Aug 02 '18 02:08 jfm-so

A user's private key should never go in here without additional strong protections, such as encrypting the key properly in the database.

As a general rule: not your key, not your coins. Same for sharing it. Sometimes when there is no other option you just have enough coins you can lose on a web wallet.

The user can just spend to their Web wallet and dispense with importing private keys.

auscash avatar Aug 16 '19 01:08 auscash