【Swift4.0】keythereum.jsをSwiftから使う【Ethereum】

[モバイル版Geth](https://github.com/ethereum/go-ethereum/wiki/Mobile:-Introduction)にはキーストアファイル(UTC/JSON)をエクスポートするメソッドが用意されているが、プライベートキー(秘密鍵)を取得するメソッドは用意されていないので、定番であるkeythereum.jsをローカルのhtml経由で読み込みWKWebViewのインスタンスメソッドであるevaluateJavaScript()にてプライベートキーを取得するアプリを作ってみました。
ちなみにJavaScriptCoreにての稼働も試みましたが戻り値がUndefinedとなってしまいます。おそらくプリミティブな型しかサポートしていないのでしょう。

### 完成イメージ
<img width="345" alt="key1.png" src="https://qiita-image-store.s3.amazonaws.com/0/151314/0422daf5-a578-f2e3-0f56-9f73cb5acca7.png">

Extract Private Keyボタンを押すと、UTC/JSONとpasswordをインプットにプライベートキーのデコードを試みます。成功した場合は画面下部にプライベートキーのバイト列が、失敗時はエラーメッセージを表示します。

# 手順

## 1.  keythereum.min.jsをダウンロード
まずは[github](https://github.com/ethereumjs/keythereum)からkeythereum.min.jsをいただきます。distフォルダの中にあります。

## 2.  keythereum.htmlを作成

###### プライベートキーを取得するjsコード

```javascript
var privateKey = keythereum.recover(password, keyObject)
```

今回のキモはこのコードをSwiftから実行できるようにすることです。
Node.jsなしでも動くブラウザベース版を利用します。

```html
<script src="keythereum.min.js" type="text/javascript"></script>
```

keythereum.html

```html
<html>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<script src="keythereum.min.js" type="text/javascript"></script>
<script>
function privateKey(keyStoreJsonStr,password) {
    var keyObject = JSON.parse(keyStoreJsonStr);
    return keythereum.recover(password, keyObject).toString('hex');
}
</script>
</head>
</html>
```

keythereum.recover()のパラメタkeyObjectはJSONオブジェクトであるためストリングで渡せるようにラップしたpraivateKey()をhtmlに記述します。


## 3. プロジェクト作成／jsとhtmlを登録

シングルビューアプリケーションをテンプレートにプロジェクトを作成します。
keythereum.min.jsとkeythereum.htmlをプロジェクトにドラッグ・アンド・ドロップするか、Build Phase->Copy Bundle Resourcesから登録します。
<img width="1400" alt="key11.png" src="https://qiita-image-store.s3.amazonaws.com/0/151314/6d02dbcf-6d3e-6838-5f72-9417fcb318e2.png">

## 4. UI作成
ストーリーボードにてUIを作成します。
ViewController.swift内のアウトレット変数と紐付けるオブジェクトを赤矢印で示しました。
<img width="1635" alt="key12.png" src="https://qiita-image-store.s3.amazonaws.com/0/151314/b895c0f4-d7e8-ec6f-1457-cb8a0f866a28.png">



## 5. ViewControllerの実装

ViewController.swift

```swift

import UIKit
import WebKit

class ViewController: UIViewController {

    @IBOutlet weak var keyStoreText:UITextView!
    @IBOutlet weak var passwordField:UITextField!
    @IBOutlet weak var secretKeyLabel:UILabel!
    
    // ダミーのWebview. JS実行用
    //var webView = UIWebView()
    var webView = WKWebView()
    // テキストフィールド外をタップするとキーボードを隠す
    @IBAction func hiddenKeyboard(_ sender: UITapGestureRecognizer) {
        self.view.endEditing(true)
    }

    @IBAction func extractPrivateKey(_ sender:UIButton) {
        
        // javascript:privateKey()のパラメタ
        var param1:String = ""
        let param2 = passwordField.text!
        // keyStoreTextの複数行を１行にする
        keyStoreText.text?.enumerateLines { (line, stop) -> () in
            param1 += line.trimmingCharacters(in:.whitespacesAndNewlines)
        }
        
        // js評価文字列作成
        let jsEvalStr = "privateKey('" + param1 + "','" + param2 + "');"
        
        //let privateKey = webView.stringByEvaluatingJavaScript(from:jsEvalStr)
        webView.evaluateJavaScript(jsEvalStr, completionHandler: {(res,error) in
            guard let pk = res else {
                self.secretKeyLabel.text = "fail to decode private key"
                return
            }
            
            self.secretKeyLabel.text = pk as? String
        })

    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        // ローカルのkeythereum.htmlをロード
//        let html = Bundle.main.path(forResource: "keythereum", ofType: "html")
//        webView.loadRequest(URLRequest(url: URL(string: html!)!))
        
        let url = Bundle.main.url(forResource: "keythereum", withExtension: ".html")!
        let urlRequest = URLRequest(url: url)
        webView.load(urlRequest)
        
        // パスワードフィールドを伏せ字モードに
        passwordField.isSecureTextEntry = true

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}
// Xcode 9.1 Swift4.0
```


UIWebViewのインスタンスメソッドであるstringByEvaluatingJavaScript()をコールするためにサイズ未指定でウェブビューをインスタンスしています。

```swift
//var webView = UIWebView()
var webView = WKWebView()
```
###### 

テキストビューの内容を改行とホワイトスペースを除きながら１行にしています。

```swift
keyStoreText.text?.enumerateLines { (line, stop) -> () in
    param1 += line.trimmingCharacters(in:.whitespacesAndNewlines)
}
```

javascript実行コード文字列を編集しています。

```swift
let jsEvalStr = "privateKey('" + param1 + "','" + param2 + "');"
 ```

## 6. 稼働確認

抽出されたプライベートキーが正しいかどうかは[EthTools.com](https://ethtools.com/mainnet/wallet/load/)で確認するのが便利です。

Keyfileをクリック
<img width="1400" alt="key5.png" src="https://qiita-image-store.s3.amazonaws.com/0/151314/b2a0495f-b43f-e8fe-65cc-34cabe92b12a.png">

UTC/JSONをペースト、パスワードを入れて、Load Walletをクリック
<img width="1400" alt="key7.png" src="https://qiita-image-store.s3.amazonaws.com/0/151314/9092eb96-ceaf-8c06-ff2d-237649d2c7b8.png">

Advanced(+)をクリックするとPrivate keyを見ることが出来ます
<img width="1405" alt="key8.png" src="https://qiita-image-store.s3.amazonaws.com/0/151314/955b46f3-affb-0a37-ed81-512f0ea89534.png">

合ってます＼(^o^)／
<img width="345" alt="key10.png" src="https://qiita-image-store.s3.amazonaws.com/0/151314/2e68e7e9-140a-068c-e364-257a15d26181.png">

githubに置いときます
[KeythereumSwift](https://github.com/fromageblanc/KeythereumSwift)


|<font color="Red">Caution!! </font>|
|---|
|<font color="Red">紹介しておいてなんですが、プライベートキーはとても大切な情報です。本運用しているアカウントのプライベートキーをむやみにウェブで入力したりすることはおすすめできません。 </font>  |

## 2017.12.13改修 
UIWebViewでなくWKWebViewを使用するように改修しました