Skip to content

Commit

Permalink
fix: ship our own metamask stub
Browse files Browse the repository at this point in the history
this prevents the need for 'unsafe-inline' in the CSP to talk to MM on Firefox
  • Loading branch information
mrnerdhair committed Nov 18, 2021
1 parent dddb885 commit 265d59e
Show file tree
Hide file tree
Showing 6 changed files with 213 additions and 9 deletions.
1 change: 0 additions & 1 deletion headers.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ const cspMeta = Object.entries({
'script-src': [
"'self'",
"'unsafe-eval'", //TODO: There are still a couple of libraries we depend on that use eval; notably amqp-ts and google-protobuf.
"'unsafe-inline'", //TODO: The only inline code we need is the stub injected by Metamask. We can fix this by including the stub in our own bundle.
"'report-sample'"
],
'style-src': ["'self'", "'unsafe-inline'", "'report-sample'"],
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,10 @@
"localforage": "^1.10.0",
"lodash": "^4.17.21",
"match-sorter": "^6.3.0",
"metamask-inpage-provider": "^5.0.0",
"node-polyglot": "^2.4.0",
"numeral": "^2.0.6",
"post-message-stream": "^3.0.0",
"qr-image": "^3.2.0",
"qs": "^6.10.1",
"react": "^17.0.2",
Expand Down Expand Up @@ -138,6 +140,7 @@
"@types/node": "^16.4.10",
"@types/node-polyglot": "^2.4.2",
"@types/numeral": "^2.0.1",
"@types/post-message-stream": "^3.0.1",
"@types/qr-image": "^3.2.4",
"@types/react": "^17.0.15",
"@types/react-dom": "^17.0.9",
Expand Down
17 changes: 17 additions & 0 deletions src/lib/metamaskInpageProvider.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
declare module 'metamask-inpage-provider' {
import type PostMessageStream from 'post-message-stream'

export function initProvider({
connectionStream,
maxEventListeners = 100,
preventPropertyDeletion = true,
shouldSendMetadata = true,
shouldSetOnWindow = true
}: {
connectionStream: PostMessageStream
maxEventListeners?: number
preventPropertyDeletion?: boolean
shouldSendMetadata?: boolean
shouldSetOnWindow?: boolean
}): unknown
}
103 changes: 103 additions & 0 deletions src/lib/metamaskInpageProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/// <reference path="./metamaskInpageProvider.d.ts" />

import { initProvider } from 'metamask-inpage-provider'
import PostMessageStream from 'post-message-stream'

function universalProxy(pseudoTarget: object) {
return {
proxy: new Proxy(
{},
new Proxy(
{},
{
get(_, p) {
return (_t: any, p2: any, r: any) => {
switch (p) {
case 'get': {
const out = Reflect.get(pseudoTarget, p2, r)
if (typeof out === 'function') return out.bind(pseudoTarget)
return out
}
case 'getOwnPropertyDescriptor': {
const out = Reflect.getOwnPropertyDescriptor(pseudoTarget, p2)
if (out) out.configurable = true
return out
}
case 'isExtensible':
return true
case 'preventExtensions':
return false
default:
return (Reflect as any)[p](pseudoTarget, p2, r)
}
}
}
}
)
),
getPseudoTarget() {
return pseudoTarget
},
setPseudoTarget(value: object) {
pseudoTarget = value
}
}
}

if (typeof window !== 'undefined') {
const initialPseudoTarget = Object.freeze({})
const { proxy, getPseudoTarget, setPseudoTarget } = universalProxy(
window.ethereum ?? initialPseudoTarget
)
try {
Object.defineProperty(window, 'ethereum', {
configurable: true,
enumerable: true,
get() {
return proxy
},
set(value: unknown) {
if (!(value && ['object', 'function'].includes(typeof value))) throw new TypeError()
setPseudoTarget(value as object)
}
})

// Allow MM time to try to sucessfully execute its own injected stub
setTimeout(() => {
try {
// Don't clobber an existing MM stub
if (getPseudoTarget() !== initialPseudoTarget) {
console.info('metamaskInpageProvider: MM stub was already injected')
return
}
initProvider({
connectionStream: new PostMessageStream({
name: 'inpage',
target: 'contentscript'
})
})
if (window.ethereum.isMetaMask) {
console.info('metamaskInpageProvider: injected MM stub')
} else {
console.info(
'metamaskInpageProvider: MM stub injection failed:',
window.ethereum,
getPseudoTarget()
)
}
} catch (e) {
console.error('metamaskInpageProvider callback:', e)
} finally {
Object.defineProperty(window, 'ethereum', {
configurable: true,
enumerable: true,
writable: true,
value: getPseudoTarget()
})
console.info('metamaskInpageProvider: window.ethereum proxy reset')
}
}, 0)
} catch (e) {
console.error('metamaskInpageProvider:', e)
}
}
1 change: 1 addition & 0 deletions src/lib/polyfills.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,4 @@ import '@formatjs/intl-pluralrules/locale-data/tr'
import '@formatjs/intl-pluralrules/locale-data/uk'
import '@formatjs/intl-pluralrules/locale-data/vi'
import '@formatjs/intl-pluralrules/locale-data/zh'
import './metamaskInpageProvider'
97 changes: 89 additions & 8 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5293,6 +5293,13 @@
dependencies:
"@types/node" "*"

"@types/post-message-stream@^3.0.1":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@types/post-message-stream/-/post-message-stream-3.0.1.tgz#919aad3921812647fe7b0a27637d47445f887c3f"
integrity sha512-j9X5t0bpDezd/pCLCddMUIWv4m3gdqrK95c3Utdw6zylv7caoyWskcJ1YjhtftAk2A70f+WtLqeedTr0lqQxzQ==
dependencies:
"@types/readable-stream" "*"

"@types/prettier@^2.0.0":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.4.1.tgz#e1303048d5389563e130f5bdd89d37a99acb75eb"
Expand Down Expand Up @@ -5410,6 +5417,14 @@
"@types/scheduler" "*"
csstype "^3.0.2"

"@types/readable-stream@*":
version "2.3.11"
resolved "https://registry.yarnpkg.com/@types/readable-stream/-/readable-stream-2.3.11.tgz#942bc4574a1d7ca4368cb9cb4352e3d2b4b51dea"
integrity sha512-0z+/apYJwKFz/RHp6mOMxz/y7xOvWPYPevuCEyAY3gXsjtaac02E26RvxA+I96rfvmVH/dEMGXNvyJfViR1FSQ==
dependencies:
"@types/node" "*"
safe-buffer "*"

"@types/resolve@0.0.8":
version "0.0.8"
resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.8.tgz#f26074d238e02659e323ce1a13d041eee280e194"
Expand Down Expand Up @@ -9575,7 +9590,7 @@ encodeurl@~1.0.2:
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=

end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1:
end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.0, end-of-stream@^1.4.1:
version "1.4.4"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
Expand Down Expand Up @@ -10105,6 +10120,13 @@ eth-ens-namehash@2.0.8:
idna-uts46-hx "^2.3.1"
js-sha3 "^0.5.7"

eth-json-rpc-errors@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/eth-json-rpc-errors/-/eth-json-rpc-errors-2.0.2.tgz#c1965de0301fe941c058e928bebaba2e1285e3c4"
integrity sha512-uBCRM2w2ewusRHGxN8JhcuOb2RN3ueAOYH/0BhqdFmQkZx5lj5+fLKTz0mIVOzd4FG5/kUksCzCD7eTEim6gaA==
dependencies:
fast-safe-stringify "^2.0.6"

eth-json-rpc-filters@^4.2.1:
version "4.2.2"
resolved "https://registry.yarnpkg.com/eth-json-rpc-filters/-/eth-json-rpc-filters-4.2.2.tgz#eb35e1dfe9357ace8a8908e7daee80b2cd60a10d"
Expand Down Expand Up @@ -10700,6 +10722,11 @@ fake-merkle-patricia-tree@^1.0.1:
dependencies:
checkpoint-store "^1.1.0"

fast-deep-equal@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=

fast-deep-equal@^3.0.0, fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
Expand Down Expand Up @@ -13561,7 +13588,7 @@ json-parse-even-better-errors@^2.3.0:
resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==

json-rpc-engine@^5.3.0:
json-rpc-engine@^5.1.5, json-rpc-engine@^5.3.0:
version "5.4.0"
resolved "https://registry.yarnpkg.com/json-rpc-engine/-/json-rpc-engine-5.4.0.tgz#75758609d849e1dba1e09021ae473f3ab63161e5"
integrity sha512-rAffKbPoNDjuRnXkecTjnsE3xLLrb00rEkdgalINhaYVYIxDwWtvYBr9UFbhTvPB1B2qUOLoFd/cV6f4Q7mh7g==
Expand All @@ -13577,6 +13604,14 @@ json-rpc-engine@^6.1.0:
"@metamask/safe-event-emitter" "^2.0.0"
eth-rpc-errors "^4.0.2"

json-rpc-middleware-stream@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/json-rpc-middleware-stream/-/json-rpc-middleware-stream-2.1.1.tgz#06e5409e201e7ddeae47bef29f7059eafd4d5325"
integrity sha512-WZheufPN+/RKkjXQP3lK5tFYblqG0n+oYv5qpammwwY2vsJRB7mM4Txhr4ajzvYEZi1UkENnplrmaYiqaqafaA==
dependencies:
readable-stream "^2.3.3"
safe-event-emitter "^1.0.1"

json-rpc-random-id@^1.0.0, json-rpc-random-id@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/json-rpc-random-id/-/json-rpc-random-id-1.0.1.tgz#ba49d96aded1444dbb8da3d203748acbbcdec8c8"
Expand Down Expand Up @@ -14082,6 +14117,11 @@ log-update@^4.0.0:
slice-ansi "^4.0.0"
wrap-ansi "^6.2.0"

loglevel@^1.6.1:
version "1.8.0"
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.8.0.tgz#e7ec73a57e1e7b419cb6c6ac06bf050b67356114"
integrity sha512-G6A/nJLRgWOuuwdNuA6koovfEV1YpqqAG4pRUlFaz3jj2QNZ8M4vBqnVA+HBTmU/AMNUtlOsMmSpF6NyOjztbA==

loglevel@^1.6.8:
version "1.7.1"
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.1.tgz#005fde2f5e6e47068f935ff28573e125ef72f197"
Expand Down Expand Up @@ -14436,6 +14476,21 @@ merkle-patricia-tree@^2.1.2, merkle-patricia-tree@^2.3.2:
rlp "^2.0.0"
semaphore ">=1.0.1"

metamask-inpage-provider@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/metamask-inpage-provider/-/metamask-inpage-provider-5.0.0.tgz#8655a2cacd5139573b885de8bd1d41f32dad8c82"
integrity sha512-nJpevOENFJ5Ah5WJNlFj7TsFibuCI6F1UVraD+HtD2qTtee5NrPFsrP8vCjPM+XTXcHw9Vp2vyqgi7LhmRVCOg==
dependencies:
eth-json-rpc-errors "^2.0.2"
fast-deep-equal "^2.0.1"
json-rpc-engine "^5.1.5"
json-rpc-middleware-stream "^2.1.1"
loglevel "^1.6.1"
obj-multiplex "^1.0.0"
obs-store "^4.0.3"
pump "^3.0.0"
safe-event-emitter "^1.0.1"

methods@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
Expand Down Expand Up @@ -15134,6 +15189,15 @@ oauth-sign@~0.9.0:
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==

obj-multiplex@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/obj-multiplex/-/obj-multiplex-1.0.0.tgz#2f2ae6bfd4ae11befe742ea9ea5b36636eabffc1"
integrity sha1-Lyrmv9SuEb7+dC6p6ls2Y26r/8E=
dependencies:
end-of-stream "^1.4.0"
once "^1.4.0"
readable-stream "^2.3.3"

object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
Expand Down Expand Up @@ -15251,6 +15315,16 @@ oboe@2.1.5:
dependencies:
http-https "^1.0.0"

obs-store@^4.0.3:
version "4.0.3"
resolved "https://registry.yarnpkg.com/obs-store/-/obs-store-4.0.3.tgz#b632ec7814baa604fae084a4c97e87c0b7a6d14c"
integrity sha512-+mm13kCRDv6IcvUDKTw0LIy5+dQhIktYaR/RwwZUFzOTi/fjMaNBnk42Adb94qZqJ00qWkjhQSZH7MXlKnTi8A==
dependencies:
readable-stream "^2.2.2"
safe-event-emitter "^1.0.1"
through2 "^2.0.3"
xtend "^4.0.1"

obuf@^1.0.0, obuf@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e"
Expand Down Expand Up @@ -15870,6 +15944,13 @@ posix-character-classes@^0.1.0:
resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=

post-message-stream@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/post-message-stream/-/post-message-stream-3.0.0.tgz#90d9f54bd209e6b6f5d74795b87588205b547048"
integrity sha1-kNn1S9IJ5rb110eVuHWIIFtUcEg=
dependencies:
readable-stream "^2.1.4"

postcss-attribute-case-insensitive@^4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-4.0.2.tgz#d93e46b504589e94ac7277b0463226c68041a880"
Expand Down Expand Up @@ -17468,7 +17549,7 @@ read-pkg@^5.2.0:
parse-json "^5.0.0"
type-fest "^0.6.0"

"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6:
"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6:
version "2.3.7"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
Expand Down Expand Up @@ -18107,6 +18188,11 @@ safari-14-idb-fix@^3.0.0:
resolved "https://registry.yarnpkg.com/safari-14-idb-fix/-/safari-14-idb-fix-3.0.0.tgz#450fc049b996ec7f3fd9ca2f89d32e0761583440"
integrity sha512-eBNFLob4PMq8JA1dGyFn6G97q3/WzNtFK4RnzT1fnLq+9RyrGknzYiM/9B12MnKAxuj1IXr7UKYtTNtjyKMBog==

safe-buffer@*, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==

safe-buffer@5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853"
Expand All @@ -18117,11 +18203,6 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==

safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==

safe-event-emitter@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/safe-event-emitter/-/safe-event-emitter-1.0.1.tgz#5b692ef22329ed8f69fdce607e50ca734f6f20af"
Expand Down

0 comments on commit 265d59e

Please sign in to comment.