web3 opt-in updates

Signed-off-by: Andrey Shovkoplyas <motor4ik@gmail.com>
This commit is contained in:
Andrey Shovkoplyas 2018-09-05 18:31:57 +03:00
parent a79eca1e23
commit a20facd895
No known key found for this signature in database
GPG Key ID: EAAB7C8622D860A4
12 changed files with 277 additions and 92 deletions

View File

@ -6,6 +6,17 @@ function bridgeSend(data){
WebViewBridge.send(JSON.stringify(data));
}
window.addEventListener('message', function (event) {
if (!event.data || !event.data.type) { return; }
if (event.data.type === 'STATUS_API_REQUEST') {
bridgeSend({
type: 'status-api-request',
permissions: event.data.permissions,
host: window.location.hostname
});
}
});
WebViewBridge.onMessage = function (message) {
data = JSON.parse(message);
@ -14,16 +25,9 @@ WebViewBridge.onMessage = function (message) {
else if (data.type === "status-api-success")
{
if (data.keys == 'WEB3')
{
window.dispatchEvent(new CustomEvent('ethereumprovider', { detail: { ethereum: new StatusHttpProvider("")} }));
}
else
{
window.dispatchEvent(new CustomEvent('statusapi', { detail: { permissions: data.keys,
data: data.data
} }));
}
window.dispatchEvent(new CustomEvent('statusapi', { detail: { permissions: data.keys,
data: data.data
} }));
}
else if (data.type === "web3-send-async-callback")
@ -113,6 +117,10 @@ StatusHttpProvider.prototype.sendAsync = function (payload, callback) {
}
};
StatusHttpProvider.prototype.enable = function () {
return new Promise(function (resolve, reject) { setTimeout(resolve, 1000);});
};
}
var protocol = window.location.protocol
@ -120,7 +128,8 @@ if (typeof web3 === "undefined") {
//why do we need this condition?
if (protocol == "https:" || protocol == "http:") {
console.log("StatusHttpProvider");
web3 = new Web3(new StatusHttpProvider());
web3.eth.defaultAccount = currentAccountAddress; // currentAccountAddress - injected from status-react
ethereum = new StatusHttpProvider();
web3 = new Web3(ethereum);
web3.eth.defaultAccount = currentAccountAddress;
}
}

152
resources/js/web3_opt_in.js Normal file
View File

@ -0,0 +1,152 @@
if(typeof ReadOnlyProvider === "undefined"){
var callbackId = 0;
var callbacks = {};
var ethereumPromise = {};
function bridgeSend(data){
WebViewBridge.send(JSON.stringify(data));
}
window.addEventListener('message', function (event) {
if (!event.data || !event.data.type) { return; }
if (event.data.type === 'STATUS_API_REQUEST') {
bridgeSend({
type: 'status-api-request',
permissions: event.data.permissions,
host: window.location.hostname
});
}
});
WebViewBridge.onMessage = function (message) {
data = JSON.parse(message);
if (data.type === "navigate-to-blank")
window.location.href = "about:blank";
else if (data.type === "status-api-success")
{
if (data.keys == 'WEB3')
{
ethereumPromise.allowed = true;
window.currentAccountAddress = data.data["WEB3"];
ethereumPromise.resolve();
}
else
{
window.dispatchEvent(new CustomEvent('statusapi', { detail: { permissions: data.keys,
data: data.data
} }));
}
}
else if (data.type === "web3-permission-request-denied")
{
ethereumPromise.reject(new Error("Denied"));
}
else if (data.type === "web3-send-async-callback")
{
var id = data.messageId;
var callback = callbacks[id];
if (callback) {
if (callback.results)
{
callback.results.push(data.error || data.result);
if (callback.results.length == callback.num)
callback.callback(undefined, callback.results);
}
else
{
callback.callback(data.error, data.result);
}
}
}
};
function web3Response (payload, result){
return {id: payload.id,
jsonrpc: "2.0",
result: result};
}
function getSyncResponse (payload) {
console.log("getSyncResponse " + payload.method + " !")
if (payload.method == "eth_accounts" && currentAccountAddress){
return web3Response(payload, [currentAccountAddress])
} else if (payload.method == "eth_coinbase" && currentAccountAddress){
return web3Response(payload, currentAccountAddress)
} else if (payload.method == "net_version"){
return web3Response(payload, networkId)
} else if (payload.method == "eth_uninstallFilter"){
return web3Response(payload, true);
} else {
return null;
}
}
var ReadOnlyProvider = function () {};
ReadOnlyProvider.prototype.isConnected = function () { return true; };
ReadOnlyProvider.prototype.send = function (payload) {
if (payload.method == "eth_uninstallFilter"){
this.sendAsync(payload, function (res, err) {})
}
var syncResponse = getSyncResponse(payload);
if (syncResponse){
return syncResponse;
} else {
return web3Response(payload, null);
}
};
ReadOnlyProvider.prototype.enable = function () {
bridgeSend({
type: 'status-api-request',
permissions: ['WEB3'],
host: window.location.hostname
});
return new Promise(function (resolve, reject) {
ethereumPromise.resolve = resolve;
ethereumPromise.reject = reject;
});
};
ReadOnlyProvider.prototype.sendAsync = function (payload, callback) {
var syncResponse = getSyncResponse(payload);
if (syncResponse && callback){
callback(null, syncResponse);
}
else {
var messageId = callbackId++;
if (Array.isArray(payload))
{
callbacks[messageId] = {num: payload.length,
results: [],
callback: callback};
for (var i in payload) {
bridgeSend({type: 'web3-send-async-read-only',
messageId: messageId,
payload: payload[i],
host: window.location.hostname});
}
}
else
{
callbacks[messageId] = {callback: callback};
bridgeSend({type: 'web3-send-async-read-only',
messageId: messageId,
payload: payload,
host: window.location.hostname});
}
}
};
}
console.log("ReadOnlyProvider");
ethereum = new ReadOnlyProvider();

View File

@ -1,8 +1,4 @@
(function () {
function bridgeSend(data){
WebViewBridge.send(JSON.stringify(data));
}
var history = window.history;
var pushState = history.pushState;
history.pushState = function(state) {
@ -14,22 +10,4 @@
}, 100);
return pushState.apply(history, arguments);
};
window.addEventListener('message', function (event) {
if (!event.data || !event.data.type) { return; }
if (event.data.type === 'STATUS_API_REQUEST') {
bridgeSend({
type: 'status-api-request',
permissions: event.data.permissions,
host: window.location.hostname
});
}
else if (event.data.type === 'ETHEREUM_PROVIDER_REQUEST') {
bridgeSend({
type: 'status-api-request',
permissions: ['WEB3'],
host: window.location.hostname
});
}
});
}());
}());

View File

@ -43,3 +43,9 @@
(if dev-mode?
{:dev-server/start nil}
{:dev-server/stop nil})))
(defn switch-web3-opt-in-mode [opt-in {:keys [db] :as cofx}]
(let [settings (get-in db [:account/account :settings])]
(accounts.update/update-settings
(assoc settings :web3-opt-in? opt-in)
cofx)))

View File

@ -176,9 +176,9 @@
(def ^:const send-transaction-failed-parse-response 1)
(def ^:const send-transaction-failed-parse-params 2)
(def ^:const send-transaction-no-account-selected 3)
(def ^:const send-transaction-invalid-tx-sender 4)
(def ^:const send-transaction-err-decrypt 5)
(def ^:const send-transaction-no-account-selected 3)
(def ^:const send-transaction-invalid-tx-sender 4)
(def ^:const send-transaction-err-decrypt 5)
(def ^:const web3-send-transaction "eth_sendTransaction")
(def ^:const web3-personal-sign "personal_sign")
@ -193,6 +193,8 @@
(def ^:const dapp-permission-web3 "WEB3")
(def ^:const status-api-success "status-api-success")
(def ^:const status-api-request "status-api-request")
(def ^:const web3-permission-request-denied "web3-permission-request-denied")
(def ^:const history-state-changed "history-state-changed")
(def ^:const web3-send-async "web3-send-async")
(def ^:const web3-send-async-read-only "web3-send-async-read-only")
(def ^:const web3-send-async-callback "web3-send-async-callback")

View File

@ -107,6 +107,11 @@
(fn [cofx [_ dev-mode?]]
(accounts/switch-dev-mode dev-mode? cofx)))
(handlers/register-handler-fx
:accounts.ui/web3-opt-in-mode-switched
(fn [cofx [_ opt-in]]
(accounts/switch-web3-opt-in-mode opt-in cofx)))
(handlers/register-handler-fx
:accounts.ui/wallet-set-up-confirmed
(fn [cofx [_ modal?]]

View File

@ -123,6 +123,10 @@
:keys (keys permissions-allowed)}
(:webview-bridge db)])
(and (zero? (count permissions-allowed)) (= constants/dapp-permission-web3 (first requested-permissions)))
(assoc :send-to-bridge-fx [{:type constants/web3-permission-request-denied}
(:webview-bridge db)])
true
(assoc :dispatch [:check-permissions-queue]))))
@ -148,6 +152,17 @@
:error %1
:result %2}])]}))
(defn web3-send-async-read-only [dapp-name {:keys [method] :as payload} message-id {:keys [db] :as cofx}]
(let [{:dapps/keys [permissions]} db]
(if (and (#{"eth_accounts" "eth_coinbase" "eth_sendTransaction" "eth_sign"
"eth_signTypedData" "personal_sign" "personal_ecRecover"} method)
(not (some #{"WEB3"} (get-in permissions [dapp-name :permissions]))))
{:dispatch [:send-to-bridge
{:type constants/web3-send-async-callback
:messageId message-id
:error "Denied"}]}
(web3-send-async payload message-id cofx))))
(defn initialize-browsers
[{:keys [db all-stored-browsers]}]
(let [browsers (into {} (map #(vector (:browser-id %) %) all-stored-browsers))]

View File

@ -14,7 +14,8 @@
[status-im.utils.types :as types]
[status-im.utils.universal-links.core :as utils.universal-links]
[taoensso.timbre :as log]
[status-im.utils.ethereum.resolver :as resolver]))
[status-im.utils.ethereum.resolver :as resolver]
[status-im.utils.ethereum.core :as ethereum]))
(re-frame/reg-fx
:browse
@ -127,7 +128,9 @@
{:keys [browser-id]} options
browser (get browsers browser-id)
data (types/json->clj message)
{{:keys [url]} :navState :keys [type host permissions payload messageId]} data]
{{:keys [url]} :navState :keys [type host permissions payload messageId]} data
{:keys [dapp? name]} browser
dapp-name (if dapp? name host)]
(cond
(and (= type constants/history-state-changed) platform/ios? (not= "about:blank" url))
@ -136,12 +139,13 @@
(= type constants/web3-send-async)
(model/web3-send-async payload messageId cofx)
(= type constants/web3-send-async-read-only)
(model/web3-send-async-read-only dapp-name payload messageId cofx)
(= type constants/status-api-request)
(let [{:keys [dapp? name]} browser
dapp-name (if dapp? name host)]
{:db (update-in db [:browser/options :permissions-queue] conj {:dapp-name dapp-name
:permissions permissions})
:dispatch [:check-permissions-queue]})))))
{:db (update-in db [:browser/options :permissions-queue] conj {:dapp-name dapp-name
:permissions permissions})
:dispatch [:check-permissions-queue]}))))
(handlers/register-handler-fx
:check-permissions-queue
@ -158,7 +162,9 @@
:index 0
:user-permissions (get-in db [:dapps/permissions dapp-name :permissions])
:requested-permissions permissions
:permissions-data {constants/dapp-permission-contact-code (:public-key account)}})))))))
:permissions-data {constants/dapp-permission-contact-code (:public-key account)
constants/dapp-permission-web3 (ethereum/normalized-address
(:address account))}})))))))
(handlers/register-handler-fx
:next-dapp-permission

View File

@ -114,14 +114,15 @@
(views/defview browser []
(views/letsubs [webview (atom nil)
{:keys [address]} [:get-current-account]
{:keys [address settings]} [:get-current-account]
{:keys [browser-id dapp? name] :as browser} [:get-current-browser]
{:keys [error? loading? url-editing? show-tooltip show-permission resolving?]} [:get :browser/options]
rpc-url [:get :rpc-url]
network-id [:get-network-id]]
(let [can-go-back? (model/can-go-back? browser)
can-go-forward? (model/can-go-forward? browser)
url (model/get-current-url browser)]
url (model/get-current-url browser)
opt-in? (:web3-opt-in? settings)]
[react/view styles/browser
[status-bar/status-bar]
[toolbar webview error? url browser browser-id url-editing?]
@ -142,12 +143,14 @@
:on-load #(re-frame/dispatch [:update-browser-options {:error? false}])
:on-error #(re-frame/dispatch [:update-browser-options {:error? true
:loading? false}])
:injected-on-start-loading-java-script (str js-res/web3
:injected-on-start-loading-java-script (str (not opt-in?) js-res/web3
(get-inject-js url)
(js-res/web3-init
rpc-url
(ethereum/normalized-address address)
(str network-id)))
(if opt-in?
(js-res/web3-opt-in-init (str network-id))
(js-res/web3-init
rpc-url
(ethereum/normalized-address address)
(str network-id))))
:injected-java-script js-res/webview-js}]
(when (or loading? resolving?)
[react/view styles/web-view-loading

View File

@ -136,48 +136,52 @@
:hide-arrow? true
:action-fn #(re-frame/dispatch [:accounts.logout.ui/logout-pressed])}]]]]))
(defview advanced-settings [{:keys [network networks dev-mode?]} on-show]
(letsubs [{:keys [sharing-usage-data?]} [:get-current-account]]
{:component-did-mount on-show}
[react/view
(when (and config/extensions-enabled? dev-mode?)
[profile.components/settings-item
{:label-kw :t/extensions
:action-fn #(re-frame/dispatch [:navigate-to :extensions-settings])
:accessibility-label :extensions-button}])
(when dev-mode?
[profile.components/settings-item
{:label-kw :t/network
:value (get-in networks [network :name])
:action-fn #(re-frame/dispatch [:navigate-to :network-settings])
:accessibility-label :network-button}])
[profile.components/settings-item-separator]
(defview advanced-settings [{:keys [network networks dev-mode? settings]} on-show]
{:component-did-mount on-show}
[react/view
(when (and config/extensions-enabled? dev-mode?)
[profile.components/settings-item
{:label-kw :t/offline-messaging
:action-fn #(re-frame/dispatch [:navigate-to :offline-messaging-settings])
:accessibility-label :offline-messages-settings-button}]
[profile.components/settings-item-separator]
{:label-kw :t/extensions
:action-fn #(re-frame/dispatch [:navigate-to :extensions-settings])
:accessibility-label :extensions-button}])
(when dev-mode?
[profile.components/settings-item
{:label-kw :t/log-level
:action-fn #(re-frame/dispatch [:navigate-to :log-level-settings])
:accessibility-label :log-level-settings-button}]
[profile.components/settings-item-separator]
{:label-kw :t/network
:value (get-in networks [network :name])
:action-fn #(re-frame/dispatch [:navigate-to :network-settings])
:accessibility-label :network-button}])
[profile.components/settings-item-separator]
[profile.components/settings-item
{:label-kw :t/offline-messaging
:action-fn #(re-frame/dispatch [:navigate-to :offline-messaging-settings])
:accessibility-label :offline-messages-settings-button}]
[profile.components/settings-item-separator]
[profile.components/settings-item
{:label-kw :t/log-level
:action-fn #(re-frame/dispatch [:navigate-to :log-level-settings])
:accessibility-label :log-level-settings-button}]
[profile.components/settings-item-separator]
[profile.components/settings-item
{:label-kw :t/fleet
:action-fn #(re-frame/dispatch [:navigate-to :fleet-settings])
:accessibility-label :fleet-settings-button}]
(when config/bootnodes-settings-enabled?
[profile.components/settings-item-separator])
(when config/bootnodes-settings-enabled?
[profile.components/settings-item
{:label-kw :t/fleet
:action-fn #(re-frame/dispatch [:navigate-to :fleet-settings])
:accessibility-label :fleet-settings-button}]
(when config/bootnodes-settings-enabled?
[profile.components/settings-item-separator])
(when config/bootnodes-settings-enabled?
[profile.components/settings-item
{:label-kw :t/bootnodes
:action-fn #(re-frame/dispatch [:navigate-to :bootnodes-settings])
:accessibility-label :bootnodes-settings-button}])
[profile.components/settings-item-separator]
{:label-kw :t/bootnodes
:action-fn #(re-frame/dispatch [:navigate-to :bootnodes-settings])
:accessibility-label :bootnodes-settings-button}])
(when dev-mode?
[profile.components/settings-switch-item
{:label-kw :t/dev-mode
:value dev-mode?
:action-fn #(re-frame/dispatch [:accounts.ui/dev-mode-switched %])}]]))
{:label-kw :t/web3-opt-in
:value (:web3-opt-in? settings)
:action-fn #(re-frame/dispatch [:accounts.ui/web3-opt-in-mode-switched %])}])
[profile.components/settings-item-separator]
[profile.components/settings-switch-item
{:label-kw :t/dev-mode
:value dev-mode?
:action-fn #(re-frame/dispatch [:accounts.ui/dev-mode-switched %])}]])
(defview advanced [params on-show]
(letsubs [advanced? [:get :my-profile/advanced?]]

View File

@ -20,6 +20,10 @@
"var networkId = \"" network-id "\";"
(slurp "resources/js/web3_init.js")))
(defn web3-opt-in-init [network-id]
(str "var networkId = \"" network-id "\";"
(slurp "resources/js/web3_opt_in.js")))
(defn local-storage-data [data]
(str "var localStorageData = " (or data "{}") ";"))

View File

@ -683,5 +683,6 @@
"gwei": "Gwei",
"cost-fee": "Cost/Fee",
"currency-display-name-usd": "United States Dollar",
"currency-display-name-uah": "Ukraine Hryvnia"
"currency-display-name-uah": "Ukraine Hryvnia",
"web3-opt-in": "Opt-in web3 provider access"
}