Commit 62e0e180 authored by obscuren's avatar obscuren

Changed public whisper api not to reveal temporary private keys

parent bb55307a
import QtQuick 2.0 import QtQuick 2.1
import QtWebKit 3.0 import QtWebKit 3.0
import QtWebKit.experimental 1.0 import QtWebKit.experimental 1.0
import QtQuick.Controls 1.0; import QtQuick.Controls 1.0;
...@@ -8,441 +8,474 @@ import QtQuick.Window 2.1; ...@@ -8,441 +8,474 @@ import QtQuick.Window 2.1;
import Ethereum 1.0 import Ethereum 1.0
Rectangle { Rectangle {
id: window id: window
property var title: "Browser" property var title: "Browser"
property var iconSource: "../browser.png" property var iconSource: "../browser.png"
property var menuItem property var menuItem
property alias url: webview.url property alias url: webview.url
property alias webView: webview property alias webView: webview
property var cleanPath: false property var cleanPath: false
property var open: function(url) { property var open: function(url) {
if(!window.cleanPath) { if(!window.cleanPath) {
var uri = url; var uri = url;
if(!/.*\:\/\/.*/.test(uri)) { if(!/.*\:\/\/.*/.test(uri)) {
uri = "http://" + uri; uri = "http://" + uri;
} }
var reg = /(^https?\:\/\/(?:www\.)?)([a-zA-Z0-9_\-]*\.eth)(.*)/ var reg = /(^https?\:\/\/(?:www\.)?)([a-zA-Z0-9_\-]*\.eth)(.*)/
if(reg.test(uri)) { if(reg.test(uri)) {
uri.replace(reg, function(match, pre, domain, path) { uri.replace(reg, function(match, pre, domain, path) {
uri = pre; uri = pre;
var lookup = eth.lookupDomain(domain.substring(0, domain.length - 4)); var lookup = eth.lookupDomain(domain.substring(0, domain.length - 4));
var ip = []; var ip = [];
for(var i = 0, l = lookup.length; i < l; i++) { for(var i = 0, l = lookup.length; i < l; i++) {
ip.push(lookup.charCodeAt(i)) ip.push(lookup.charCodeAt(i))
} }
if(ip.length != 0) { if(ip.length != 0) {
uri += lookup; uri += lookup;
} else { } else {
uri += domain; uri += domain;
} }
uri += path; uri += path;
}); });
} }
window.cleanPath = true; window.cleanPath = true;
webview.url = uri; webview.url = uri;
//uriNav.text = uri.text.replace(/(^https?\:\/\/(?:www\.)?)([a-zA-Z0-9_\-]*\.\w{2,3})(.*)/, "$1$2<span style='color:#CCC'>$3</span>"); //uriNav.text = uri.text.replace(/(^https?\:\/\/(?:www\.)?)([a-zA-Z0-9_\-]*\.\w{2,3})(.*)/, "$1$2<span style='color:#CCC'>$3</span>");
uriNav.text = uri; uriNav.text = uri;
} else { } else {
// Prevent inf loop. // Prevent inf loop.
window.cleanPath = false; window.cleanPath = false;
} }
} }
Component.onCompleted: { Component.onCompleted: {
webview.url = "http://etherian.io" webview.url = "http://etherian.io"
} }
signal messages(var messages, int id); signal messages(var messages, int id);
onMessages: { onMessages: {
// Bit of a cheat to get proper JSON // Bit of a cheat to get proper JSON
var m = JSON.parse(JSON.parse(JSON.stringify(messages))) var m = JSON.parse(JSON.parse(JSON.stringify(messages)))
webview.postEvent("eth_changed", id, m); webview.postEvent("eth_changed", id, m);
} }
function onShhMessage(message, id) { function onShhMessage(message, id) {
webview.postEvent("shh_changed", id, message) webview.postEvent("shh_changed", id, message)
} }
Item { Item {
objectName: "root" objectName: "root"
id: root id: root
anchors.fill: parent anchors.fill: parent
state: "inspectorShown" state: "inspectorShown"
RowLayout { RowLayout {
id: navBar id: navBar
height: 40 height: 40
anchors { anchors {
left: parent.left left: parent.left
right: parent.right right: parent.right
leftMargin: 7 leftMargin: 7
} }
Button { Button {
id: back id: back
onClicked: { onClicked: {
webview.goBack() webview.goBack()
} }
style: ButtonStyle { style: ButtonStyle {
background: Image { background: Image {
source: "../back.png" source: "../back.png"
width: 30 width: 30
height: 30 height: 30
} }
} }
} }
TextField { TextField {
anchors { anchors {
left: back.right left: back.right
right: toggleInspector.left right: toggleInspector.left
leftMargin: 5 leftMargin: 5
rightMargin: 5 rightMargin: 5
} }
//text: "http://etherian.io" //text: "http://etherian.io"
text: webview.url; text: webview.url;
id: uriNav id: uriNav
y: parent.height / 2 - this.height / 2 y: parent.height / 2 - this.height / 2
Keys.onReturnPressed: { Keys.onReturnPressed: {
webview.url = this.text; webview.url = this.text;
} }
} }
Button { Button {
id: toggleInspector id: toggleInspector
anchors { anchors {
right: parent.right right: parent.right
} }
iconSource: "../bug.png" iconSource: "../bug.png"
onClicked: { onClicked: {
if(inspector.visible == true){ if(inspector.visible == true){
inspector.visible = false inspector.visible = false
}else{ }else{
inspector.visible = true inspector.visible = true
inspector.url = webview.experimental.remoteInspectorUrl inspector.url = webview.experimental.remoteInspectorUrl
} }
} }
} }
} }
WebView { WebView {
objectName: "webView" objectName: "webView"
id: webview id: webview
anchors { anchors {
left: parent.left left: parent.left
right: parent.right right: parent.right
bottom: parent.bottom bottom: parent.bottom
top: navBar.bottom top: navBar.bottom
} }
//property var cleanPath: false //property var cleanPath: false
onNavigationRequested: { onNavigationRequested: {
window.open(request.url.toString()); window.open(request.url.toString());
} }
function injectJs(js) { function injectJs(js) {
webview.experimental.navigatorQtObjectEnabled = true; webview.experimental.navigatorQtObjectEnabled = true;
webview.experimental.evaluateJavaScript(js) webview.experimental.evaluateJavaScript(js)
webview.experimental.javascriptEnabled = true; webview.experimental.javascriptEnabled = true;
} }
function sendMessage(data) { function sendMessage(data) {
webview.experimental.postMessage(JSON.stringify(data)) webview.experimental.postMessage(JSON.stringify(data))
} }
experimental.preferences.javascriptEnabled: true experimental.preferences.javascriptEnabled: true
experimental.preferences.navigatorQtObjectEnabled: true experimental.preferences.webGLEnabled: true
experimental.preferences.developerExtrasEnabled: true experimental.itemSelector: MouseArea {
experimental.userScripts: ["../ext/q.js", "../ext/ethereum.js/lib/web3.js", "../ext/ethereum.js/lib/qt.js", "../ext/setup.js"] // To avoid conflicting with ListView.model when inside Initiator context.
experimental.onMessageReceived: { property QtObject selectorModel: model
console.log("[onMessageReceived]: ", message.data) anchors.fill: parent
// TODO move to messaging.js onClicked: selectorModel.reject()
var data = JSON.parse(message.data)
Menu {
try { visible: true
switch(data.call) { id: itemSelector
case "eth_compile":
postData(data._id, eth.compile(data.args[0])) Instantiator {
break model: selectorModel.items
delegate: MenuItem {
case "eth_coinbase": text: model.text
postData(data._id, eth.coinBase()) onTriggered: {
selectorModel.accept(index)
case "eth_account": }
postData(data._id, eth.key().address); }
onObjectAdded: itemSelector.insertItem(index, object)
case "eth_istening": onObjectRemoved: itemSelector.removeItem(object)
postData(data._id, eth.isListening()) }
}
break
Component.onCompleted: {
case "eth_mining": itemSelector.popup()
postData(data._id, eth.isMining()) }
}
break experimental.preferences.webAudioEnabled: true
experimental.preferences.navigatorQtObjectEnabled: true
case "eth_peerCount": experimental.preferences.developerExtrasEnabled: true
postData(data._id, eth.peerCount()) experimental.userScripts: ["../ext/q.js", "../ext/ethereum.js/lib/web3.js", "../ext/ethereum.js/lib/qt.js", "../ext/setup.js"]
experimental.onMessageReceived: {
break console.log("[onMessageReceived]: ", message.data)
// TODO move to messaging.js
case "eth_countAt": var data = JSON.parse(message.data)
require(1)
postData(data._id, eth.txCountAt(data.args[0])) try {
switch(data.call) {
break case "eth_compile":
postData(data._id, eth.compile(data.args[0]))
case "eth_codeAt": break
require(1)
var code = eth.codeAt(data.args[0]) case "eth_coinbase":
postData(data._id, code); postData(data._id, eth.coinBase())
break case "eth_account":
postData(data._id, eth.key().address);
case "eth_blockByNumber":
require(1) case "eth_istening":
var block = eth.blockByNumber(data.args[0]) postData(data._id, eth.isListening())
postData(data._id, block)
break break
case "eth_mining":
postData(data._id, eth.isMining())
break
case "eth_peerCount":
postData(data._id, eth.peerCount())
case "eth_blockByHash": break
require(1)
var block = eth.blockByHash(data.args[0])
postData(data._id, block)
break
require(2) case "eth_countAt":
var block = eth.blockByHash(data.args[0]) require(1)
postData(data._id, block.transactions[data.args[1]]) postData(data._id, eth.txCountAt(data.args[0]))
break
case "eth_transactionByHash": break
case "eth_transactionByNumber":
require(2)
var block; case "eth_codeAt":
if (data.call === "transactionByHash") require(1)
block = eth.blockByHash(data.args[0]) var code = eth.codeAt(data.args[0])
else postData(data._id, code);
block = eth.blockByNumber(data.args[0])
var tx = block.transactions.get(data.args[1]) break
postData(data._id, tx) case "eth_blockByNumber":
break require(1)
var block = eth.blockByNumber(data.args[0])
postData(data._id, block)
break
case "eth_uncleByHash": case "eth_blockByHash":
case "eth_uncleByNumber": require(1)
require(2) var block = eth.blockByHash(data.args[0])
postData(data._id, block)
break
var block; require(2)
if (data.call === "uncleByHash") var block = eth.blockByHash(data.args[0])
block = eth.blockByHash(data.args[0]) postData(data._id, block.transactions[data.args[1]])
else break
block = eth.blockByNumber(data.args[0])
var uncle = block.uncles.get(data.args[1]) case "eth_transactionByHash":
case "eth_transactionByNumber":
require(2)
postData(data._id, uncle) var block;
if (data.call === "transactionByHash")
block = eth.blockByHash(data.args[0])
else
block = eth.blockByNumber(data.args[0])
break var tx = block.transactions.get(data.args[1])
case "transact": postData(data._id, tx)
require(5) break
var tx = eth.transact(data.args) case "eth_uncleByHash":
postData(data._id, tx) case "eth_uncleByNumber":
require(2)
break var block;
if (data.call === "uncleByHash")
block = eth.blockByHash(data.args[0])
else
block = eth.blockByNumber(data.args[0])
case "eth_stateAt": var uncle = block.uncles.get(data.args[1])
require(2);
var storage = eth.storageAt(data.args[0], data.args[1]); postData(data._id, uncle)
postData(data._id, storage)
break break
case "eth_call": case "transact":
require(1); require(5)
var ret = eth.call(data.args)
postData(data._id, ret)
break
case "eth_balanceAt": var tx = eth.transact(data.args)
require(1); postData(data._id, tx)
postData(data._id, eth.balanceAt(data.args[0])); break
break
case "eth_watch": case "eth_stateAt":
require(2) require(2);
eth.watch(data.args[0], data.args[1])
case "eth_disconnect": var storage = eth.storageAt(data.args[0], data.args[1]);
require(1) postData(data._id, storage)
postData(data._id, null)
break;
case "eth_newFilterString": break
require(1)
var id = eth.newFilterString(data.args[0])
postData(data._id, id);
break;
case "eth_newFilter": case "eth_call":
require(1) require(1);
var id = eth.newFilter(data.args[0]) var ret = eth.call(data.args)
postData(data._id, ret)
break
postData(data._id, id); case "eth_balanceAt":
break; require(1);
case "eth_filterLogs": postData(data._id, eth.balanceAt(data.args[0]));
require(1); break
var messages = eth.messages(data.args[0]); case "eth_watch":
var m = JSON.parse(JSON.parse(JSON.stringify(messages))) require(2)
postData(data._id, m); eth.watch(data.args[0], data.args[1])
break; case "eth_disconnect":
require(1)
postData(data._id, null)
break;
case "eth_deleteFilter": case "eth_newFilterString":
require(1); require(1)
eth.uninstallFilter(data.args[0]) var id = eth.newFilterString(data.args[0])
break; postData(data._id, id);
break;
case "eth_newFilter":
require(1)
var id = eth.newFilter(data.args[0])
case "shh_newFilter": postData(data._id, id);
require(1); break;
var id = shh.watch(data.args[0], window);
postData(data._id, id);
break;
case "shh_newIdentity": case "eth_filterLogs":
var id = shh.newIdentity() require(1);
postData(data._id, id)
break var messages = eth.messages(data.args[0]);
var m = JSON.parse(JSON.parse(JSON.stringify(messages)))
postData(data._id, m);
case "shh_post": break;
require(1);
var params = data.args[0]; case "eth_deleteFilter":
var fields = ["payload", "to", "from"]; require(1);
for(var i = 0; i < fields.length; i++) { eth.uninstallFilter(data.args[0])
params[fields[i]] = params[fields[i]] || ""; break;
case "shh_newFilter":
require(1);
var id = shh.watch(data.args[0], window);
postData(data._id, id);
break;
case "shh_newIdentity":
var id = shh.newIdentity()
postData(data._id, id)
break
case "shh_post":
require(1);
var params = data.args[0];
var fields = ["payload", "to", "from"];
for(var i = 0; i < fields.length; i++) {
params[fields[i]] = params[fields[i]] || "";
}
if(typeof params.payload !== "object") { params.payload = [params.payload]; } //params.payload = params.payload.join(""); }
params.topics = params.topics || [];
params.priority = params.priority || 1000;
params.ttl = params.ttl || 100;
shh.post(params.payload, params.to, params.from, params.topics, params.priority, params.ttl);
break;
case "shh_getMessages":
require(1);
var m = shh.messages(data.args[0]);
var messages = JSON.parse(JSON.parse(JSON.stringify(m)));
postData(data._id, messages);
break;
case "ssh_newGroup":
postData(data._id, "");
break;
}
} catch(e) {
console.log(data.call + ": " + e)
postData(data._id, null);
}
}
function post(seed, data) {
postData(data._id, data)
}
function require(args, num) {
if(args.length < num) {
throw("required argument count of "+num+" got "+args.length);
}
}
function postData(seed, data) {
webview.experimental.postMessage(JSON.stringify({data: data, _id: seed}))
}
function postEvent(event, id, data) {
webview.experimental.postMessage(JSON.stringify({data: data, _id: id, _event: event}))
}
function onWatchedCb(data, id) {
var messages = JSON.parse(data)
postEvent("watched:"+id, messages)
}
function onNewBlockCb(block) {
postEvent("block:new", block)
}
function onObjectChangeCb(stateObject) {
postEvent("object:"+stateObject.address(), stateObject)
}
function onStorageChangeCb(storageObject) {
var ev = ["storage", storageObject.stateAddress, storageObject.address].join(":");
postEvent(ev, [storageObject.address, storageObject.value])
}
}
Rectangle {
id: sizeGrip
color: "gray"
visible: false
height: 10
anchors {
left: root.left
right: root.right
}
y: Math.round(root.height * 2 / 3)
MouseArea {
anchors.fill: parent
drag.target: sizeGrip
drag.minimumY: 0
drag.maximumY: root.height
drag.axis: Drag.YAxis
}
}
WebView {
id: inspector
visible: false
anchors {
left: root.left
right: root.right
top: sizeGrip.bottom
bottom: root.bottom
}
}
states: [
State {
name: "inspectorShown"
PropertyChanges {
target: inspector
} }
if(typeof params.payload !== "object") { params.payload = [params.payload]; } //params.payload = params.payload.join(""); } }
params.topics = params.topics || []; ]
params.priority = params.priority || 1000; }
params.ttl = params.ttl || 100;
shh.post(params.payload, params.to, params.from, params.topics, params.priority, params.ttl);
break;
case "shh_getMessages":
require(1);
var m = shh.messages(data.args[0]);
var messages = JSON.parse(JSON.parse(JSON.stringify(m)));
postData(data._id, messages);
break;
}
} catch(e) {
console.log(data.call + ": " + e)
postData(data._id, null);
}
}
function post(seed, data) {
postData(data._id, data)
}
function require(args, num) {
if(args.length < num) {
throw("required argument count of "+num+" got "+args.length);
}
}
function postData(seed, data) {
webview.experimental.postMessage(JSON.stringify({data: data, _id: seed}))
}
function postEvent(event, id, data) {
webview.experimental.postMessage(JSON.stringify({data: data, _id: id, _event: event}))
}
function onWatchedCb(data, id) {
var messages = JSON.parse(data)
postEvent("watched:"+id, messages)
}
function onNewBlockCb(block) {
postEvent("block:new", block)
}
function onObjectChangeCb(stateObject) {
postEvent("object:"+stateObject.address(), stateObject)
}
function onStorageChangeCb(storageObject) {
var ev = ["storage", storageObject.stateAddress, storageObject.address].join(":");
postEvent(ev, [storageObject.address, storageObject.value])
}
}
Rectangle {
id: sizeGrip
color: "gray"
visible: false
height: 10
anchors {
left: root.left
right: root.right
}
y: Math.round(root.height * 2 / 3)
MouseArea {
anchors.fill: parent
drag.target: sizeGrip
drag.minimumY: 0
drag.maximumY: root.height
drag.axis: Drag.YAxis
}
}
WebView {
id: inspector
visible: false
anchors {
left: root.left
right: root.right
top: sizeGrip.bottom
bottom: root.bottom
}
}
states: [
State {
name: "inspectorShown"
PropertyChanges {
target: inspector
}
}
]
}
} }
...@@ -17,7 +17,7 @@ func ToQMessage(msg *whisper.Message) *Message { ...@@ -17,7 +17,7 @@ func ToQMessage(msg *whisper.Message) *Message {
return &Message{ return &Message{
ref: msg, ref: msg,
Flags: int32(msg.Flags), Flags: int32(msg.Flags),
Payload: ethutil.Bytes2Hex(msg.Payload), Payload: "0x" + ethutil.Bytes2Hex(msg.Payload),
From: ethutil.Bytes2Hex(crypto.FromECDSAPub(msg.Recover())), From: "0x" + ethutil.Bytes2Hex(crypto.FromECDSAPub(msg.Recover())),
} }
} }
...@@ -41,32 +41,41 @@ func (self *Whisper) Post(payload []string, to, from string, topics []string, pr ...@@ -41,32 +41,41 @@ func (self *Whisper) Post(payload []string, to, from string, topics []string, pr
data = append(data, fromHex(d)...) data = append(data, fromHex(d)...)
} }
msg := whisper.NewMessage(data) pk := crypto.ToECDSAPub(fromHex(from))
envelope, err := msg.Seal(time.Duration(priority*100000), whisper.Opts{ if key := self.Whisper.GetIdentity(pk); key != nil {
Ttl: time.Duration(ttl) * time.Second, msg := whisper.NewMessage(data)
To: crypto.ToECDSAPub(fromHex(to)), envelope, err := msg.Seal(time.Duration(priority*100000), whisper.Opts{
From: crypto.ToECDSA(fromHex(from)), Ttl: time.Duration(ttl) * time.Second,
Topics: whisper.TopicsFromString(topics...), To: crypto.ToECDSAPub(fromHex(to)),
}) From: key,
if err != nil { Topics: whisper.TopicsFromString(topics...),
qlogger.Infoln(err) })
// handle error
return if err != nil {
} qlogger.Infoln(err)
// handle error
return
}
if err := self.Whisper.Send(envelope); err != nil { if err := self.Whisper.Send(envelope); err != nil {
qlogger.Infoln(err) qlogger.Infoln(err)
// handle error // handle error
return return
}
} else {
qlogger.Infoln("unmatched pub / priv for seal")
} }
} }
func (self *Whisper) NewIdentity() string { func (self *Whisper) NewIdentity() string {
return toHex(self.Whisper.NewIdentity().D.Bytes()) key := self.Whisper.NewIdentity()
return toHex(crypto.FromECDSAPub(&key.PublicKey))
} }
func (self *Whisper) HasIdentity(key string) bool { func (self *Whisper) HasIdentity(key string) bool {
return self.Whisper.HasIdentity(crypto.ToECDSA(fromHex(key))) return self.Whisper.HasIdentity(crypto.ToECDSAPub(fromHex(key)))
} }
func (self *Whisper) Watch(opts map[string]interface{}, view *qml.Common) int { func (self *Whisper) Watch(opts map[string]interface{}, view *qml.Common) int {
......
...@@ -60,7 +60,7 @@ type Whisper struct { ...@@ -60,7 +60,7 @@ type Whisper struct {
quit chan struct{} quit chan struct{}
keys []*ecdsa.PrivateKey keys map[string]*ecdsa.PrivateKey
} }
func New() *Whisper { func New() *Whisper {
...@@ -69,6 +69,7 @@ func New() *Whisper { ...@@ -69,6 +69,7 @@ func New() *Whisper {
filters: filter.New(), filters: filter.New(),
expiry: make(map[uint32]*set.SetNonTS), expiry: make(map[uint32]*set.SetNonTS),
quit: make(chan struct{}), quit: make(chan struct{}),
keys: make(map[string]*ecdsa.PrivateKey),
} }
whisper.filters.Start() whisper.filters.Start()
...@@ -101,18 +102,18 @@ func (self *Whisper) NewIdentity() *ecdsa.PrivateKey { ...@@ -101,18 +102,18 @@ func (self *Whisper) NewIdentity() *ecdsa.PrivateKey {
if err != nil { if err != nil {
panic(err) panic(err)
} }
self.keys = append(self.keys, key)
self.keys[string(crypto.FromECDSAPub(&key.PublicKey))] = key
return key return key
} }
func (self *Whisper) HasIdentity(key *ecdsa.PrivateKey) bool { func (self *Whisper) HasIdentity(key *ecdsa.PublicKey) bool {
for _, key := range self.keys { return self.keys[string(crypto.FromECDSAPub(key))] != nil
if key.D.Cmp(key.D) == 0 { }
return true
} func (self *Whisper) GetIdentity(key *ecdsa.PublicKey) *ecdsa.PrivateKey {
} return self.keys[string(crypto.FromECDSAPub(key))]
return false
} }
func (self *Whisper) Watch(opts Filter) int { func (self *Whisper) Watch(opts Filter) int {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment