wrote out architecture rant in readme
@@ -1,5 +1,177 @@
|
|||||||
# Jack Russell Extension
|
# Jack Russell Extension
|
||||||
|
|
||||||
## File Tree
|
This is a browser extension wallet for the Aeternity payment network. It is
|
||||||
|
meant to work in the latest versions of Firefox and Chromium.
|
||||||
|
|
||||||
|
## How it works
|
||||||
|
|
||||||
|
You may want to read about how [AWCP](../libs/awcp/src/awcp.ts) and
|
||||||
|
[Sidekick](../sidekick/src/sidekick.ts) work first. Briefly,
|
||||||
|
|
||||||
|
- AWCP (Aepp-Waellet Communication Protocol) defines the message protocol
|
||||||
|
between a page script (the "aepp") and a wallet (the "waellet"). A page
|
||||||
|
script is something that you include with `<script src="./foo/bar.js">`
|
||||||
|
- Sidekick is a library (for page scripts) of TS/JS function calls that
|
||||||
|
blackboxes away all of the stupid implementation detail nonsense about how to
|
||||||
|
actually send and recieve the messages defined by AWCP. For instance, there
|
||||||
|
is a function call `tx_sign_noprop`, where you hand that function a
|
||||||
|
transaction, and the return value is either the signed transaction or an
|
||||||
|
error (for instance, the user rejected the signature request).
|
||||||
|
|
||||||
|
JR works in a very similar way to Sidekick, but it has more things that need to
|
||||||
|
talk to other things layers. Browser extensions have 3 basic components:
|
||||||
|
|
||||||
|
1. Content scripts. These are almost the same thing as page scripts.
|
||||||
|
|
||||||
|
In general, content scripts are typically used to modify websites the
|
||||||
|
end-user is looking at. For instance, if you were making RedBorder, an
|
||||||
|
extension that adds a 15 pixel wide red border around every image, the
|
||||||
|
content script is the part of RedBorder that has the permission to query
|
||||||
|
the DOM for `<img>` tags, and modify each such tag to have the property
|
||||||
|
`style="border: 15px solid red;"`.
|
||||||
|
|
||||||
|
For the purposes of JR, the content script is simply the messaging layer
|
||||||
|
between the page script and the rest of the extension. All that matters in
|
||||||
|
our case is
|
||||||
|
- the content script can post messages that are visible to page scripts
|
||||||
|
- vice versa
|
||||||
|
- the content script has permission to send messages to other parts of our
|
||||||
|
extension (and to other extensions and to desktop applictions and it can
|
||||||
|
eat your children but that doesn't matter)
|
||||||
|
- vice versa
|
||||||
|
|
||||||
|
2. The background script.
|
||||||
|
|
||||||
|
This is the central controller of the application.
|
||||||
|
|
||||||
|
3. Popup scripts.
|
||||||
|
|
||||||
|
This is what a "popup" is in the context of browser extensions:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
This is an HTML page like any other. A popup script is simply a script
|
||||||
|
that runs in the context of the popup page. It has the same basic array of
|
||||||
|
permissions as the background script.
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
PAGE SCRIPT <-> CONTENT SCRIPT <-> BACKGROUND SCRIPT <-> POPUP SCRIPT
|
||||||
|
Aegora.jp <-> src/content.ts <-> src/background.ts <-> src/popup.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
In JavaScript, the standard way of communicating between mutually opaque
|
||||||
|
contexts A and B (for instance, between a page script and a wallet) is to write
|
||||||
|
a class in each context that manages state, which listens for events, and then
|
||||||
|
does things in response to those events. `ClassA` can dispatch events which are
|
||||||
|
visible to the event listener in `ClassB` and vice versa. This is the natural
|
||||||
|
result of trying to shoehorn concurrency into an object-oriented language.
|
||||||
|
|
||||||
|
Sidekick and JR internally work by mimicking Erlang's interprocess
|
||||||
|
communication (IPC) idiom.
|
||||||
|
|
||||||
|
Erlang is a concurrency-first language, and thus has a much saner and more
|
||||||
|
well-thought-out approach to this problem. There is a build-in function called
|
||||||
|
`send(PID, Message)`. The message can be any Erlang term. In the receiving
|
||||||
|
process, there is primitive syntax for receiving messages:
|
||||||
|
|
||||||
|
```erl
|
||||||
|
receive
|
||||||
|
Pattern1 ->
|
||||||
|
do_thing_1();
|
||||||
|
Pattern2 ->
|
||||||
|
do_thing_2();
|
||||||
|
_ ->
|
||||||
|
handle_arbitrary_message()
|
||||||
|
after NMilliseconds ->
|
||||||
|
do_timeout_thing()
|
||||||
|
end.
|
||||||
|
```
|
||||||
|
|
||||||
|
Each process has a mailbox. When a process enters a `receive`, it sits there
|
||||||
|
and scans its mailbox to find a message that matches one of the patterns. If
|
||||||
|
it finds a message that matches `Pattern1`, it executes the function
|
||||||
|
`do_thing_1()`, and so on. The `after` part is optional, and it exists as a
|
||||||
|
backstop so the process doesn't get stuck in an infinite `receive` loop.
|
||||||
|
|
||||||
|
Here is an example of two processes just exchanging ping and pong:
|
||||||
|
|
||||||
|
```erl
|
||||||
|
#!/usr/bin/env escript
|
||||||
|
|
||||||
|
-mode(compile).
|
||||||
|
|
||||||
|
%% this is the code that is run by the pinger process
|
||||||
|
pinger() ->
|
||||||
|
%% the pinger just sits and waits until a pong message appears in the
|
||||||
|
%% mailbox and sends back ping
|
||||||
|
receive
|
||||||
|
%% wait to receive a pong
|
||||||
|
%% only accept this pattern
|
||||||
|
{SenderPID, pong} ->
|
||||||
|
%% self() gets the current process pid
|
||||||
|
%% print out the pong to the console
|
||||||
|
ok = io:format("~p received pong from ~p~n", [self(), SenderPID]),
|
||||||
|
%% wait for 1 second
|
||||||
|
ok = timer:sleep(1000),
|
||||||
|
%% send a ping back
|
||||||
|
SenderPID ! {self(), ping},
|
||||||
|
%% start over
|
||||||
|
pinger()
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
%% this is the code that is run by the ponger process
|
||||||
|
%% identical to the pinger except the words "ping" and "pong" have been swapped
|
||||||
|
ponger() ->
|
||||||
|
%% the ponger just sits and waits until a ping message appears in the
|
||||||
|
%% mailbox and sends back pong
|
||||||
|
receive
|
||||||
|
%% wait to receive a ping
|
||||||
|
%% only accept this pattern
|
||||||
|
{SenderPID, ping} ->
|
||||||
|
%% self gets the current process's pid
|
||||||
|
%% print out the ping to the console
|
||||||
|
ok = io:format("~p received ping from ~p~n", [self(), SenderPID]),
|
||||||
|
%% wait for 1 second
|
||||||
|
ok = timer:sleep(1000),
|
||||||
|
%% send a pong back
|
||||||
|
SenderPID ! {self(), pong},
|
||||||
|
%% start over
|
||||||
|
ponger()
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
%% this is the main process
|
||||||
|
main([]) ->
|
||||||
|
%% start up pingers and pongers
|
||||||
|
%% these just sit and wait until they are told to do something
|
||||||
|
PingerPID = spawn(fun pinger/0),
|
||||||
|
PongerPID = spawn(fun ponger/0),
|
||||||
|
%% ping the ponger, but lie about who is doing it
|
||||||
|
PongerPID ! {PingerPID, ping},
|
||||||
|
%% this is a hack so that main doesn't exit and therefore the demo works
|
||||||
|
receive
|
||||||
|
_ ->
|
||||||
|
ok = io:format("bye~n")
|
||||||
|
end.
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
[~] % escript pingpong.erl
|
||||||
|
<0.81.0> received ping from <0.80.0>
|
||||||
|
<0.80.0> received pong from <0.81.0>
|
||||||
|
<0.81.0> received ping from <0.80.0>
|
||||||
|
<0.80.0> received pong from <0.81.0>
|
||||||
|
<0.81.0> received ping from <0.80.0>
|
||||||
|
<0.80.0> received pong from <0.81.0>
|
||||||
|
<0.81.0> received ping from <0.80.0>
|
||||||
|
<0.80.0> received pong from <0.81.0>
|
||||||
|
^C
|
||||||
|
```
|
||||||
|
|
||||||
|
JR basically thinks of each of the 3 different components of an extension as
|
||||||
|
Erlang processes, and has some band-aid code to kind of sort of mimick Erlang's
|
||||||
|
IPC idiom. Frankly, Erlang's IPC idiom doesn't quite fit into TS/JS, however
|
||||||
|
even the shoehorned band-aid Erlang idiom is significantly simpler and more
|
||||||
|
pleasant to work with than the OOPy event idiom.
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.8 KiB |
|
After Width: | Height: | Size: 16 KiB |
@@ -2,4 +2,5 @@
|
|||||||
{realm, local}.
|
{realm, local}.
|
||||||
{name, jrx}.
|
{name, jrx}.
|
||||||
{version, "0.1.0"}.
|
{version, "0.1.0"}.
|
||||||
{deps, ["local-tweetnacl-1.0.3"]}.
|
{deps, ["local-tweetnacl-1.0.3",
|
||||||
|
"local-awcp-0.2.1"]}.
|
||||||
|
|||||||
@@ -0,0 +1,261 @@
|
|||||||
|
/**
|
||||||
|
* JR Content Script
|
||||||
|
*
|
||||||
|
* @module
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
jr_main();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the "meat" of what is spammed to the page script when the user makes
|
||||||
|
* the wallet detectable.
|
||||||
|
*
|
||||||
|
* If you go read the AWCP documentation, there's a bunch of layers. This is I
|
||||||
|
* think the innermost layer.
|
||||||
|
*/
|
||||||
|
function detect_msg() {
|
||||||
|
return {id : "jr",
|
||||||
|
name : "JR",
|
||||||
|
networkId : "ae_uat",
|
||||||
|
origin : "foobar",
|
||||||
|
type : "extension"};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Post {@link detect_awcp_msg} into the window message queue
|
||||||
|
*/
|
||||||
|
function
|
||||||
|
post_detect_msg
|
||||||
|
(msg: object)
|
||||||
|
{
|
||||||
|
window.postMessage(msg, '*');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For 2 minutes, make the wallet detectable to a page script
|
||||||
|
*/
|
||||||
|
async function
|
||||||
|
mk_detectable
|
||||||
|
(msg: object)
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
// 3 seconds times 40 is 2 minutes
|
||||||
|
// for (let i=1; i<=40; i++)
|
||||||
|
{
|
||||||
|
console.error('pee');
|
||||||
|
post_detect_msg(msg);
|
||||||
|
await sleep(3000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sleep for the given number of ms
|
||||||
|
*/
|
||||||
|
async function
|
||||||
|
sleep
|
||||||
|
(ms: number)
|
||||||
|
: Promise<void>
|
||||||
|
{
|
||||||
|
return new Promise(resolve => setTimeout(resolve, ms));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This handles messages from *other parts of the extension*
|
||||||
|
*/
|
||||||
|
function
|
||||||
|
handler
|
||||||
|
(msg: any)
|
||||||
|
{
|
||||||
|
console.error('message: ', msg);
|
||||||
|
switch(msg)
|
||||||
|
{
|
||||||
|
case 'mk-detectable':
|
||||||
|
mk_detectable();
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
console.error('your mom is dead');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This handles messages from page scripts
|
||||||
|
*/
|
||||||
|
function
|
||||||
|
window_message_handler
|
||||||
|
(msg: {data: any})
|
||||||
|
{
|
||||||
|
console.error('the science is coming', msg);
|
||||||
|
// example science:
|
||||||
|
// {
|
||||||
|
// "type": "to_waellet",
|
||||||
|
// "data": {
|
||||||
|
// "jsonrpc": "2.0",
|
||||||
|
// "id": "ske-connect-1",
|
||||||
|
// "method": "connection.open",
|
||||||
|
// "params": {
|
||||||
|
// "name": "sidekick examples",
|
||||||
|
// "version": 1
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
let the_science = msg.data;
|
||||||
|
console.error('THE SCIENCE: ', the_science);
|
||||||
|
console.error('is the science good or bad?');
|
||||||
|
if (the_science.type === 'to_waellet')
|
||||||
|
{
|
||||||
|
console.error('the science is good');
|
||||||
|
the_science_is_good(the_science.data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
console.error('the science is bad');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* window_message_handler handles all messages sent into the event bus,
|
||||||
|
* including messages that we sent (yay js). window_message_handler branches on
|
||||||
|
* whether the message is for us or not (is the science good or bad?). If the
|
||||||
|
* message is for us (the science is good), then this function is triggered.
|
||||||
|
*
|
||||||
|
* The bottom line is this is the function that *actually* handles messages
|
||||||
|
* from the window
|
||||||
|
*/
|
||||||
|
function
|
||||||
|
the_science_is_good
|
||||||
|
(awcp_rcp_data: {id : string | number,
|
||||||
|
method : string,
|
||||||
|
params : object})
|
||||||
|
{
|
||||||
|
// example science data:
|
||||||
|
// // layer 3: json rpc
|
||||||
|
// {jsonrpc : "2.0",
|
||||||
|
// id : "ske-connect-1",
|
||||||
|
// method : "connection.open",
|
||||||
|
// // layer 4: AWCP-specific semantics
|
||||||
|
// params : {name : "sidekick examples",
|
||||||
|
// version : 1}}}
|
||||||
|
// can assume it is a call
|
||||||
|
let msg_ident = awcp_rcp_data.id;
|
||||||
|
let msg_method = awcp_rcp_data.method;
|
||||||
|
// branch here on the "method" field
|
||||||
|
switch (msg_method)
|
||||||
|
{
|
||||||
|
case "connection.open":
|
||||||
|
post_connect_msg(msg_ident);
|
||||||
|
break;
|
||||||
|
case "address.subscribe":
|
||||||
|
bg_address_subscribe(msg_ident);
|
||||||
|
break;
|
||||||
|
case "transaction.sign":
|
||||||
|
bg_tx_sign(msg_ident, awcp_rcp_data.params);
|
||||||
|
break;
|
||||||
|
case "message.sign":
|
||||||
|
bg_msg_sign(msg_ident, awcp_rcp_data.params);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.error('the science is worse than i initially thought');
|
||||||
|
console.error("we're going to have to put the science to sleep");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called in response to "connection.open" requests from page scripts
|
||||||
|
*
|
||||||
|
* FIXME: this should query the user to see if he wants to connect
|
||||||
|
*/
|
||||||
|
function
|
||||||
|
post_connect_msg
|
||||||
|
(msg_ident : string | number)
|
||||||
|
{
|
||||||
|
// : EventData_W2A_connection_open
|
||||||
|
// http://localhost:6969/local-awcp-0.2.1/types/EventData_W2A_connection_open.html
|
||||||
|
let connect_response =
|
||||||
|
{type: "to_aepp",
|
||||||
|
data: {jsonrpc: "2.0",
|
||||||
|
id: msg_ident,
|
||||||
|
method: "connection.open",
|
||||||
|
result: detect_msg()}};
|
||||||
|
window.postMessage(connect_response, '*');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called in response to "address.subscribe" requests from page scripts
|
||||||
|
*
|
||||||
|
* this is to get the wallet's address
|
||||||
|
*/
|
||||||
|
function
|
||||||
|
bg_address_subscribe
|
||||||
|
(msg_ident: string | number)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called in response to "transaction.sign" requests from page scripts
|
||||||
|
*
|
||||||
|
* user wants us to sign a transaction
|
||||||
|
*/
|
||||||
|
function
|
||||||
|
bg_tx_sign
|
||||||
|
(msg_ident : string | number,
|
||||||
|
params : object)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called in response to "message.sign" requests from page scripts
|
||||||
|
*
|
||||||
|
* user wants us to sign a message
|
||||||
|
*/
|
||||||
|
function
|
||||||
|
bg_msg_sign
|
||||||
|
(msg_ident : string | number,
|
||||||
|
params : object)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function
|
||||||
|
jr_main
|
||||||
|
()
|
||||||
|
{
|
||||||
|
// @ts-ignore browser
|
||||||
|
// browser.runtime.onMessage.addListener(handler);
|
||||||
|
window.addEventListener('message', window_message_handler);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the message that we spam the page script with when the user clicks
|
||||||
|
* the "make wallet detectable" button.
|
||||||
|
*
|
||||||
|
* Contains {@link detect_msg} as a field
|
||||||
|
*/
|
||||||
|
let detect_awcp_msg = {type : "to_aepp",
|
||||||
|
data : {jsonrpc : "2.0",
|
||||||
|
method : "connection.announcePresence",
|
||||||
|
params : detect_msg()}};
|
||||||
|
|
||||||
|
// mk detectable
|
||||||
|
mk_detectable(detect_awcp_msg);
|
||||||
|
}
|
||||||
@@ -1,246 +1,27 @@
|
|||||||
/**
|
/**
|
||||||
* JR Content Script
|
* JR Content Script
|
||||||
*
|
*
|
||||||
|
* Notes:
|
||||||
|
*
|
||||||
|
* 1. This is not loaded as a module, which means it has limited permissions.
|
||||||
|
* In particular, asynchronous calls are 1000x more annoying.
|
||||||
|
* 2. All this does is relay messages between here and the background script
|
||||||
|
* (i.e. application controller).
|
||||||
|
*
|
||||||
* @module
|
* @module
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
jr_main();
|
jr_content_main();
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the "meat" of what is spammed to the page script when the user makes
|
|
||||||
* the wallet detectable.
|
|
||||||
*
|
|
||||||
* If you go read the AWCP documentation, there's a bunch of layers. This is I
|
|
||||||
* think the innermost layer.
|
|
||||||
*/
|
|
||||||
function detect_msg() {
|
|
||||||
return {id : "jr",
|
|
||||||
name : "JR",
|
|
||||||
networkId : "ae_uat",
|
|
||||||
origin : "foobar",
|
|
||||||
type : "extension"};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Post {@link detect_awcp_msg} into the window message queue
|
|
||||||
*/
|
|
||||||
function
|
|
||||||
post_detect_msg
|
|
||||||
(msg: object)
|
|
||||||
{
|
|
||||||
window.postMessage(msg, '*');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For 2 minutes, make the wallet detectable to a page script
|
|
||||||
*/
|
|
||||||
async function
|
|
||||||
mk_detectable
|
|
||||||
(msg: object)
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
// 3 seconds times 40 is 2 minutes
|
|
||||||
// for (let i=1; i<=40; i++)
|
|
||||||
{
|
|
||||||
console.error('pee');
|
|
||||||
post_detect_msg(msg);
|
|
||||||
await sleep(3000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* sleep for the given number of ms
|
|
||||||
*/
|
|
||||||
async function
|
|
||||||
sleep
|
|
||||||
(ms: number)
|
|
||||||
: Promise<void>
|
|
||||||
{
|
|
||||||
return new Promise(resolve => setTimeout(resolve, ms));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This handles messages from *other parts of the extension*
|
|
||||||
*/
|
|
||||||
function
|
|
||||||
handler
|
|
||||||
(msg: any)
|
|
||||||
{
|
|
||||||
console.error('message: ', msg);
|
|
||||||
switch(msg)
|
|
||||||
{
|
|
||||||
case 'mk-detectable':
|
|
||||||
mk_detectable();
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
console.error('your mom is dead');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This handles messages from page scripts
|
|
||||||
*/
|
|
||||||
function
|
|
||||||
window_message_handler
|
|
||||||
(msg: {data: any})
|
|
||||||
{
|
|
||||||
console.error('the science is coming', msg);
|
|
||||||
// example science:
|
|
||||||
// {
|
|
||||||
// "type": "to_waellet",
|
|
||||||
// "data": {
|
|
||||||
// "jsonrpc": "2.0",
|
|
||||||
// "id": "ske-connect-1",
|
|
||||||
// "method": "connection.open",
|
|
||||||
// "params": {
|
|
||||||
// "name": "sidekick examples",
|
|
||||||
// "version": 1
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
let the_science = msg.data;
|
|
||||||
console.error('THE SCIENCE: ', the_science);
|
|
||||||
console.error('is the science good or bad?');
|
|
||||||
if (the_science.type === 'to_waellet')
|
|
||||||
{
|
|
||||||
console.error('the science is good');
|
|
||||||
the_science_is_good(the_science.data);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
console.error('the science is bad');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* window_message_handler handles all messages sent into the event bus,
|
|
||||||
* including messages that we sent (yay js). window_message_handler branches on
|
|
||||||
* whether the message is for us or not (is the science good or bad?). If the
|
|
||||||
* message is for us (the science is good), then this function is triggered.
|
|
||||||
*
|
|
||||||
* The bottom line is this is the function that *actually* handles messages
|
|
||||||
* from the window
|
|
||||||
*/
|
|
||||||
function
|
|
||||||
the_science_is_good
|
|
||||||
(awcp_rcp_data: {id : string | number,
|
|
||||||
method : string,
|
|
||||||
params : object})
|
|
||||||
{
|
|
||||||
// example science data:
|
|
||||||
// // layer 3: json rpc
|
|
||||||
// {jsonrpc : "2.0",
|
|
||||||
// id : "ske-connect-1",
|
|
||||||
// method : "connection.open",
|
|
||||||
// // layer 4: AWCP-specific semantics
|
|
||||||
// params : {name : "sidekick examples",
|
|
||||||
// version : 1}}}
|
|
||||||
// can assume it is a call
|
|
||||||
let msg_ident = awcp_rcp_data.id;
|
|
||||||
let msg_method = awcp_rcp_data.method;
|
|
||||||
// branch here on the "method" field
|
|
||||||
switch (msg_method)
|
|
||||||
{
|
|
||||||
case "connection.open":
|
|
||||||
post_connect_msg(msg_ident);
|
|
||||||
break;
|
|
||||||
case "address.subscribe":
|
|
||||||
bg_address_subscribe(msg_ident);
|
|
||||||
break;
|
|
||||||
case "transaction.sign":
|
|
||||||
bg_tx_sign(msg_ident, awcp_rcp_data.params);
|
|
||||||
break;
|
|
||||||
case "message.sign":
|
|
||||||
bg_msg_sign(msg_ident, awcp_rcp_data.params);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
console.error('the science is worse than i initially thought');
|
|
||||||
console.error("we're going to have to put the science to sleep");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called in response to "connection.open" requests from page scripts
|
|
||||||
*
|
|
||||||
* FIXME: this should query the user to see if he wants to connect
|
|
||||||
*/
|
|
||||||
function
|
|
||||||
post_connect_msg
|
|
||||||
(msg_ident : string | number)
|
|
||||||
{
|
|
||||||
// : EventData_W2A_connection_open
|
|
||||||
// http://localhost:6969/local-awcp-0.2.1/types/EventData_W2A_connection_open.html
|
|
||||||
let connect_response =
|
|
||||||
{type: "to_aepp",
|
|
||||||
data: {jsonrpc: "2.0",
|
|
||||||
id: msg_ident,
|
|
||||||
method: "connection.open",
|
|
||||||
result: detect_msg()}};
|
|
||||||
window.postMessage(connect_response, '*');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called in response to "address.subscribe" requests from page scripts
|
|
||||||
*
|
|
||||||
* this is to get the wallet's address
|
|
||||||
*/
|
|
||||||
function
|
|
||||||
bg_address_subscribe
|
|
||||||
(msg_ident: string | number)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called in response to "transaction.sign" requests from page scripts
|
|
||||||
*
|
|
||||||
* user wants us to sign a transaction
|
|
||||||
*/
|
|
||||||
function
|
|
||||||
bg_tx_sign
|
|
||||||
(msg_ident : string | number,
|
|
||||||
params : object)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called in response to "message.sign" requests from page scripts
|
|
||||||
*
|
|
||||||
* user wants us to sign a message
|
|
||||||
*/
|
|
||||||
function
|
|
||||||
bg_msg_sign
|
|
||||||
(msg_ident : string | number,
|
|
||||||
params : object)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async function
|
async function
|
||||||
jr_main
|
jr_content_main
|
||||||
()
|
()
|
||||||
{
|
{
|
||||||
// @ts-ignore browser
|
// @ts-ignore browser
|
||||||
// browser.runtime.onMessage.addListener(handler);
|
browser.runtime.onMessage.addListener(handler);
|
||||||
window.addEventListener('message', window_message_handler);
|
window.addEventListener('message', page_script_message_handler);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
/**
|
||||||
|
* Definitions of messages that are passed between process A and process B in
|
||||||
|
* JR. Example: how the content script talks to the background script.
|
||||||
|
*
|
||||||
|
* @module
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this is the message sent from the content script to the background script
|
||||||
|
* when a page script requests
|
||||||
|
*/
|
||||||
|
type c2b_addr_subscribe = "address_subscribe";
|
||||||