Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cd2a1ef825 |
@@ -1488,8 +1488,10 @@ view would leave a wallet one click from deletion.
|
||||
- **Transitions**:
|
||||
- "Import" with a valid entry and a matching password of at least 12
|
||||
characters → creates the wallet, clears the navigation stack, and →
|
||||
**Home**. The phrase and xprv modes then scan for further used addresses
|
||||
and report the count as a flash message.
|
||||
**Home**. When no address is active yet, as on the first wallet, the new
|
||||
wallet's first address becomes the active one. The phrase and xprv modes
|
||||
then scan for further used addresses and report the count as a flash
|
||||
message.
|
||||
- "Import" with a missing, short or mismatched password → full-sentence
|
||||
error on the error line, no screen change
|
||||
- "Import" with an invalid entry or a duplicate wallet or address → flash
|
||||
@@ -2080,12 +2082,9 @@ view would leave a wallet one click from deletion.
|
||||
`wallet_requestPermissions` and is on neither the allowed nor the denied list.
|
||||
A site is its full origin, `scheme://host[:port]`, on both lists and for a
|
||||
connection allowed without "Remember": a choice for `https://dapp.example`
|
||||
says nothing about `http://dapp.example` or another port of that host. A page
|
||||
with an opaque origin, such as one its server sandboxes with a
|
||||
Content-Security-Policy, is reported with the origin `null`, which is no site:
|
||||
every request from it is refused with EIP-1193 code `4100` and opens no
|
||||
prompt. The background script prefers the toolbar popup (`action.openPopup()`)
|
||||
and falls back to a separate popup window (`src/background/index.js`,
|
||||
says nothing about `http://dapp.example` or another port of that host. The
|
||||
background script prefers the toolbar popup (`action.openPopup()`) and falls
|
||||
back to a separate popup window (`src/background/index.js`,
|
||||
`requestApproval()`). Only one exists per site at a time: a further connection
|
||||
request from a site whose prompt is still unanswered is refused with EIP-1193
|
||||
code `-32002` and opens no new prompt. If that prompt was in a toolbar popup
|
||||
|
||||
@@ -1428,11 +1428,6 @@ runtime.onMessage.addListener((msg, sender, sendResponse) => {
|
||||
// the origin of sender.url is used: the frame that sent the message,
|
||||
// not the tab's page, which may be another site embedding that
|
||||
// frame. With neither, the request is refused.
|
||||
//
|
||||
// A page with an opaque origin, such as one its server sandboxes with
|
||||
// a Content-Security-Policy, is reported with the origin "null". That
|
||||
// is no site, so the request is refused too, and not credited to the
|
||||
// site its URL names.
|
||||
let trustedOrigin = sender.origin;
|
||||
if (!trustedOrigin && sender.url) {
|
||||
try {
|
||||
@@ -1441,7 +1436,7 @@ runtime.onMessage.addListener((msg, sender, sendResponse) => {
|
||||
// an unparseable URL leaves the origin unknown
|
||||
}
|
||||
}
|
||||
if (!trustedOrigin || trustedOrigin === "null") {
|
||||
if (!trustedOrigin) {
|
||||
sendResponse({
|
||||
error: {
|
||||
code: 4100,
|
||||
|
||||
@@ -194,6 +194,9 @@ async function importMnemonic(ctx) {
|
||||
};
|
||||
state.wallets.push(wallet);
|
||||
state.hasWallet = true;
|
||||
if (state.activeAddress === null) {
|
||||
state.activeAddress = firstAddress;
|
||||
}
|
||||
await saveState();
|
||||
clearViewStack();
|
||||
ctx.renderWalletList();
|
||||
@@ -254,6 +257,9 @@ async function importPrivateKey(ctx) {
|
||||
addresses: [{ address: addr, balance: "0.0000", tokenBalances: [] }],
|
||||
});
|
||||
state.hasWallet = true;
|
||||
if (state.activeAddress === null) {
|
||||
state.activeAddress = addr;
|
||||
}
|
||||
await saveState();
|
||||
clearViewStack();
|
||||
ctx.renderWalletList();
|
||||
@@ -315,6 +321,9 @@ async function importXprvKey(ctx) {
|
||||
};
|
||||
state.wallets.push(wallet);
|
||||
state.hasWallet = true;
|
||||
if (state.activeAddress === null) {
|
||||
state.activeAddress = firstAddress;
|
||||
}
|
||||
await saveState();
|
||||
clearViewStack();
|
||||
ctx.renderWalletList();
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
// Adding the first wallet left no address active until the popup was reopened,
|
||||
// so Send and Receive on Home only said "No active address selected."
|
||||
// (https://git.eeqj.de/sneak/AutistMask/issues/512). Each test boots a fresh
|
||||
// install, adds the first wallet through one of the three import tabs, and
|
||||
// opens Receive from Home in the same popup.
|
||||
|
||||
const { HDNodeWallet, Mnemonic, Wallet } = require("ethers");
|
||||
|
||||
const { bootPopup, cleanupPopup } = require("./support/popupBoot");
|
||||
|
||||
const PHRASE =
|
||||
"abandon abandon abandon abandon abandon abandon " +
|
||||
"abandon abandon abandon abandon abandon about";
|
||||
const PRIVATE_KEY = "0x" + "11".repeat(32);
|
||||
// The master key of PHRASE, so its first address is the phrase's.
|
||||
const XPRV = HDNodeWallet.fromSeed(
|
||||
Mnemonic.fromPhrase(PHRASE).computeSeed(),
|
||||
).extendedKey;
|
||||
const PASSWORD = "correct horse battery staple";
|
||||
|
||||
const PHRASE_ADDRESS = HDNodeWallet.fromPhrase(PHRASE).address;
|
||||
|
||||
const TABS = [
|
||||
{
|
||||
tab: "tab-mnemonic",
|
||||
field: "wallet-mnemonic",
|
||||
secret: PHRASE,
|
||||
address: PHRASE_ADDRESS,
|
||||
},
|
||||
{
|
||||
tab: "tab-privkey",
|
||||
field: "import-private-key",
|
||||
secret: PRIVATE_KEY,
|
||||
address: new Wallet(PRIVATE_KEY).address,
|
||||
},
|
||||
{
|
||||
tab: "tab-xprv",
|
||||
field: "import-xprv-key",
|
||||
secret: XPRV,
|
||||
address: PHRASE_ADDRESS,
|
||||
},
|
||||
];
|
||||
|
||||
afterEach(() => {
|
||||
cleanupPopup();
|
||||
});
|
||||
|
||||
describe("the first wallet's first address is active right away", () => {
|
||||
test.each(TABS)(
|
||||
"added from $tab, Receive opens on it",
|
||||
async ({ tab, field, secret, address }) => {
|
||||
const page = await bootPopup(undefined);
|
||||
expect(page.pageErrors).toEqual([]);
|
||||
await page.click("btn-welcome-add");
|
||||
await page.click(tab);
|
||||
page.node(field).value = secret;
|
||||
page.node("add-wallet-password").value = PASSWORD;
|
||||
page.node("add-wallet-password-confirm").value = PASSWORD;
|
||||
await page.click("btn-add-wallet-confirm");
|
||||
expect(page.visibleViews()).toEqual(["main"]);
|
||||
|
||||
await page.click("btn-main-receive");
|
||||
expect(page.visibleViews()).toEqual(["receive"]);
|
||||
expect(page.node("receive-address-block").dataset.full).toBe(
|
||||
address,
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
+2
-28
@@ -8,14 +8,8 @@
|
||||
// and a request the browser said nothing about was credited to whatever the
|
||||
// page wrote (https://git.eeqj.de/sneak/AutistMask/issues/407).
|
||||
//
|
||||
// A page with an opaque origin, such as one its server sandboxes with a
|
||||
// Content-Security-Policy, is reported with the origin "null". That names no
|
||||
// site, so its request is refused
|
||||
// (https://git.eeqj.de/sneak/AutistMask/issues/527).
|
||||
//
|
||||
// Every other sender here lacks sender.origin, as on old Firefox. The
|
||||
// connection check on eth_accounts is what shows which site a request was
|
||||
// credited to.
|
||||
// Every sender here lacks sender.origin, as on old Firefox. The connection
|
||||
// check on eth_accounts is what shows which site a request was credited to.
|
||||
|
||||
const { makeStorageStub } = require("./support/storageStub");
|
||||
|
||||
@@ -150,23 +144,3 @@ describe("a request the browser does not say the sender of", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("a request from a page with an opaque origin", () => {
|
||||
test("is refused, whatever the page's URL says", async () => {
|
||||
const accounts = loadBackground();
|
||||
|
||||
const result = await accounts({
|
||||
origin: "null",
|
||||
url: CONNECTED_ORIGIN + "/sandboxed.html",
|
||||
tab: { url: CONNECTED_ORIGIN + "/sandboxed.html" },
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
error: {
|
||||
code: 4100,
|
||||
message:
|
||||
"The wallet could not tell which site sent this request.",
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -258,12 +258,17 @@ async function bootPopup(stored, options) {
|
||||
formatAddressTotal: () => "",
|
||||
getAddressValue: () => ({ usd: null, partial: false }),
|
||||
}));
|
||||
// scanForAddresses() answers in the real one's shape, a scan that found
|
||||
// no used address: AddWallet reads `addresses` from it.
|
||||
jest.doMock("../../src/shared/balances", () => ({
|
||||
fetchTokenBalances: jest.fn(async () => []),
|
||||
refreshBalances: jest.fn(async () => {}),
|
||||
lookupTokenInfo: jest.fn(async () => null),
|
||||
getProvider: () => ({}),
|
||||
scanForAddresses: jest.fn(async () => []),
|
||||
scanForAddresses: jest.fn(async () => ({
|
||||
addresses: [],
|
||||
nextIndex: 1,
|
||||
})),
|
||||
}));
|
||||
// filterTransactions() answers in the real one's shape: Home,
|
||||
// AddressDetail and AddressToken read both fields, and a bare list makes
|
||||
|
||||
Reference in New Issue
Block a user