diff --git a/.circleci/config.yml b/.circleci/config.yml index b8666d879..76992feca 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -160,6 +160,7 @@ workflows: requires: - prep-deps - prep-build + - prep-build-flask - all-tests-pass - job-publish-storybook: filters: @@ -371,7 +372,7 @@ jobs: root: . paths: - storybook-build - + test-storybook: executor: node-browsers steps: @@ -718,8 +719,11 @@ jobs: - attach_workspace: at: . - run: - name: sentry sourcemaps upload - command: SENTRY_ORG=metamask SENTRY_PROJECT=metamask yarn sentry:publish + name: Publish main release to Sentry + command: yarn sentry:publish + - run: + name: Publish Flask release to Sentry + command: yarn sentry:publish --build-type flask - run: name: Create GitHub release command: | diff --git a/.circleci/scripts/release-create-gh-release.sh b/.circleci/scripts/release-create-gh-release.sh index 93303f576..54d3946a9 100755 --- a/.circleci/scripts/release-create-gh-release.sh +++ b/.circleci/scripts/release-create-gh-release.sh @@ -26,25 +26,53 @@ function install_github_cli () popd } +function print_flask_version () +{ + local flask_filename + flask_filename="$(find ./builds-flask -type f -name 'metamask-flask-chrome-*.zip' -exec basename {} .zip \;)" + + local flask_build_filename_prefix + flask_build_filename_prefix='metamask-flask-chrome-' + local flask_build_filename_prefix_size + flask_build_filename_prefix_size="${#flask_build_filename_prefix}" + + # Use substring parameter expansion to remove the filename prefix, leaving just the version + echo "${flask_filename:$flask_build_filename_prefix_size}" +} + +function publish_flask_tag () +{ + local flask_version="${1}"; shift + + git config user.email "metamaskbot@users.noreply.github.com" + git config user.name "MetaMask Bot" + git tag -a "v${flask_version}" -m "Flask version ${flask_version}" + repo_slug="$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME" + git push "https://$GITHUB_TOKEN@github.com/$repo_slug" "v${flask_version}" +} + current_commit_msg=$(git show -s --format='%s' HEAD) if [[ $current_commit_msg =~ Version[-[:space:]](v[[:digit:]]+.[[:digit:]]+.[[:digit:]]+) ]] then tag="${BASH_REMATCH[1]}" + flask_version="$(print_flask_version)" install_github_cli printf '%s\n' 'Creating GitHub Release' release_body="$(awk -v version="${tag##v}" -f .circleci/scripts/show-changelog.awk CHANGELOG.md)" - pushd builds - hub release create \ - --attach metamask-chrome-*.zip \ - --attach metamask-firefox-*.zip \ - --message "Version ${tag##v}" \ - --message "$release_body" \ - --commitish "$CIRCLE_SHA1" \ - "$tag" - popd + hub release create \ + --attach builds/metamask-chrome-*.zip \ + --attach builds/metamask-firefox-*.zip \ + --attach builds-flask/metamask-flask-chrome-*.zip \ + --attach builds-flask/metamask-flask-firefox-*.zip \ + --message "Version ${tag##v}" \ + --message "$release_body" \ + --commitish "$CIRCLE_SHA1" \ + "$tag" + + publish_flask_tag "${flask_version}" else printf '%s\n' 'Version not found in commit message; skipping GitHub Release' exit 0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 36c98d895..8adfd5f55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -117,6 +117,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Harden keyring type check in EthOverview ([#13711](https://github.com/MetaMask/metamask-extension/pull/13711)) - Update "Forgot Password?" copy ([#13493](https://github.com/MetaMask/metamask-extension/pull/13493)) - Confirm transaction page: use method name only for contract transactions ([#13643](https://github.com/MetaMask/metamask-extension/pull/13643)) +## [10.11.4] +### Added +- **[FLASK]** Snap removal confirmation ([#13619](https://github.com/MetaMask/metamask-extension/pull/13619)) + +### Changed +- **[FLASK]** Update MetaMask Flask + - This is the first release of [MetaMask Flask](https://metamask.io/flask) since the initial release on January 18. This release includes a significant number of fixes and DevX improvements. Flask will henceforth be released at a more frequent cadence, usually in close proximity to releases of the regular MetaMask Extension. + - For reference, [#13462](https://github.com/MetaMask/metamask-extension/pull/13462) used the feature branch that produced the original Flask release after some additional changes were made. +- **[FLASK]** Update Snaps packages to version `^0.10.6` ([#13901](https://github.com/MetaMask/metamask-extension/pull/13901), [#14041](https://github.com/MetaMask/metamask-extension/pull/14041), [#14070](https://github.com/MetaMask/metamask-extension/pull/14070)) + - Updates the following packages from `0.9.0` to `0.10.6`: + - `@metamask/iframe-execution-environment-service` + - `@metamask/rpc-methods` + - `@metamask/snap-controllers` + - Updates the targeted [`iframe-execution-environment`](https://github.com/MetaMask/iframe-execution-environment) version from `0.3.1` to `0.4.2`. + - These changes encompass a variety of fixes and devX improvements. See the [releases](https://github.com/MetaMask/snaps-skunkworks/releases) of the Snaps monorepo for details. + +### Fixed +- **[FLASK]** Various UI issues ([#13462](https://github.com/MetaMask/metamask-extension/pull/13462)) + - _Note:_ The original Flask release was cut from the feature branch of [#13462](https://github.com/MetaMask/metamask-extension/pull/13462) before it was merged. + - Fix Snaps permission request confirmation page title ([#13342](https://github.com/MetaMask/metamask-extension/pull/13342)) + - Fix Snaps custom confirmation `textarea` height ([#13572](https://github.com/MetaMask/metamask-extension/pull/13572)) + - Fix various styling issues ([#13577](https://github.com/MetaMask/metamask-extension/pull/13577)) +- **[FLASK]** Fix Snap key management install warning appearance ([#13844](https://github.com/MetaMask/metamask-extension/pull/13844)) + +## [10.11.3] +### Changed +- Split secret recovery phrase input into one-field-per-word ([#14016](https://github.com/MetaMask/metamask-extension/pull/14016)) + +## [10.11.2] +### Fixed +- Fix bug that users who are connected to another extension would hit when viewing connected sites ([#13974](https://github.com/MetaMask/metamask-extension/pull/13974)) ## [10.11.1] ### Changed @@ -2889,6 +2920,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v10.12.0...HEAD [10.12.0]: https://github.com/MetaMask/metamask-extension/compare/v10.11.1...v10.12.0 +[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v10.11.4...HEAD +[10.11.4]: https://github.com/MetaMask/metamask-extension/compare/v10.11.3...v10.11.4 +[10.11.3]: https://github.com/MetaMask/metamask-extension/compare/v10.11.2...v10.11.3 +[10.11.2]: https://github.com/MetaMask/metamask-extension/compare/v10.11.1...v10.11.2 [10.11.1]: https://github.com/MetaMask/metamask-extension/compare/v10.11.0...v10.11.1 [10.11.0]: https://github.com/MetaMask/metamask-extension/compare/v10.10.2...v10.11.0 [10.10.2]: https://github.com/MetaMask/metamask-extension/compare/v10.10.1...v10.10.2 diff --git a/app/_locales/am/messages.json b/app/_locales/am/messages.json index 8d9e27e13..998726fa6 100644 --- a/app/_locales/am/messages.json +++ b/app/_locales/am/messages.json @@ -801,9 +801,6 @@ "securityAndPrivacy": { "message": "ደህንነት እና ግላዊነት" }, - "seedPhrasePlaceholder": { - "message": "እያንዳንዱን ቃል በነጠላ ክፍት ቦታ ይለያዩ" - }, "seedPhraseReq": { "message": "የዘር ሐረጋት የ 12 ቃላት ርዝመት አላቸው" }, diff --git a/app/_locales/ar/messages.json b/app/_locales/ar/messages.json index d3e78ae7b..925a51c0a 100644 --- a/app/_locales/ar/messages.json +++ b/app/_locales/ar/messages.json @@ -817,9 +817,6 @@ "securityAndPrivacy": { "message": "الأمن والخصوصية" }, - "seedPhrasePlaceholder": { - "message": "يرجى فصل كل كلمة بمسافة واحدة" - }, "seedPhraseReq": { "message": "طول الجمل البذرية 12 كلمة" }, diff --git a/app/_locales/bg/messages.json b/app/_locales/bg/messages.json index df8c830ae..ce6c09dd5 100644 --- a/app/_locales/bg/messages.json +++ b/app/_locales/bg/messages.json @@ -812,9 +812,6 @@ "securityAndPrivacy": { "message": "Сигурност и поверителност" }, - "seedPhrasePlaceholder": { - "message": "Отделете всяка дума с един интервал" - }, "seedPhraseReq": { "message": "Фразите зародиш се състоят от 12 думи" }, diff --git a/app/_locales/bn/messages.json b/app/_locales/bn/messages.json index 7290dab16..e9a0a85fc 100644 --- a/app/_locales/bn/messages.json +++ b/app/_locales/bn/messages.json @@ -816,9 +816,6 @@ "securityAndPrivacy": { "message": "নিরাপত্তা এবং গোপনীয়তা" }, - "seedPhrasePlaceholder": { - "message": "প্রতিটি শব্দকে একটি স্পেস দিয়ে আলাদা করুন" - }, "seedPhraseReq": { "message": "সীড ফ্রেজগুলি 12 শব্দের" }, diff --git a/app/_locales/ca/messages.json b/app/_locales/ca/messages.json index ce8f14237..2d0ab7177 100644 --- a/app/_locales/ca/messages.json +++ b/app/_locales/ca/messages.json @@ -794,9 +794,6 @@ "securityAndPrivacy": { "message": "Seguretat i privacitat" }, - "seedPhrasePlaceholder": { - "message": "Separa cada paraula amb un únic espai" - }, "seedPhraseReq": { "message": "Les frases de recuperació tenen 12 paraules" }, diff --git a/app/_locales/da/messages.json b/app/_locales/da/messages.json index f6f1e92d6..0067c616c 100644 --- a/app/_locales/da/messages.json +++ b/app/_locales/da/messages.json @@ -797,9 +797,6 @@ "securityAndPrivacy": { "message": "Sikkerhed & Privatliv" }, - "seedPhrasePlaceholder": { - "message": "Adskil hvert ord med et enkelt mellemrum" - }, "seedPhraseReq": { "message": "Backupsætninger er 12 ord lange" }, diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json index a192caee0..35b7c39f5 100644 --- a/app/_locales/de/messages.json +++ b/app/_locales/de/messages.json @@ -2343,9 +2343,6 @@ "seedPhraseIntroTitleCopy": { "message": "Bevor Sie loslegen, schauen Sie sich dieses kurze Video an, um mehr über Ihre Geheime Wiederherstellungsphrase zu erfahren und wie Sie Ihre Wallet sicher halten können." }, - "seedPhrasePlaceholder": { - "message": "Trennen Sie jedes Wort durch ein einzelnes Leerzeichen." - }, "seedPhraseReq": { "message": "Seed-Wörterfolgen bestehen aus 12 Wörtern" }, @@ -2453,9 +2450,6 @@ "showRecommendations": { "message": "Empfehlungen anzeigen" }, - "showSeedPhrase": { - "message": "Geheime Wiederherstellungsphrase zeigen" - }, "showTestnetNetworks": { "message": "Test-Netzwerke anzeigen" }, diff --git a/app/_locales/el/messages.json b/app/_locales/el/messages.json index b66f85652..0de718e3c 100644 --- a/app/_locales/el/messages.json +++ b/app/_locales/el/messages.json @@ -2343,12 +2343,6 @@ "seedPhraseIntroTitleCopy": { "message": "Πριν ξεκινήσετε, παρακολουθήστε αυτό το σύντομο βίντεο για να μάθετε για τη Μυστική Φράση Ανάκτησης σας και πώς να κρατήσετε το πορτοφόλι σας ασφαλές." }, - "seedPhrasePlaceholder": { - "message": "Διαχωρίστε κάθε λέξη μ' ένα κενό" - }, - "seedPhrasePlaceholderPaste": { - "message": "Επικόλληση Μυστικής Φράσης Ανάκτησης από το πρόχειρο" - }, "seedPhraseReq": { "message": "Οι Μυστικές Φράσεις Ανάκτησης έχουν μήκος 12 λέξεων" }, @@ -2459,9 +2453,6 @@ "showRecommendations": { "message": "Εμφάνιση Προτάσεων" }, - "showSeedPhrase": { - "message": "Εμφάνιση Μυστικής Φράσης Ανάκτησης" - }, "showTestnetNetworks": { "message": "Εμφάνιση δοκιμαστικών δικτύων" }, diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 4f7b20b11..dacb1c7ab 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -2686,12 +2686,6 @@ "seedPhraseIntroTitleCopy": { "message": "Before getting started, watch this short video to learn about your Secret Recovery Phrase and how to keep your wallet safe." }, - "seedPhrasePlaceholder": { - "message": "Separate each word with a single space" - }, - "seedPhrasePlaceholderPaste": { - "message": "Enter your Secret Recovery Phrase" - }, "seedPhraseReq": { "message": "Secret Recovery Phrases contain 12, 15, 18, 21, or 24 words" }, @@ -2769,6 +2763,10 @@ "settingsSearchMatchingNotFound": { "message": "No matching results found" }, + "shorthandVersion": { + "message": "v$1", + "description": "$1 is replaced by a version string (e.g. 1.2.3)" + }, "show": { "message": "Show" }, @@ -2808,9 +2806,6 @@ "showRecommendations": { "message": "Show Recommendations" }, - "showSeedPhrase": { - "message": "Show Secret Recovery Phrase" - }, "showTestnetNetworks": { "message": "Show test networks" }, @@ -2932,6 +2927,30 @@ "spendLimitTooLarge": { "message": "Spend limit too large" }, + "srpInputNumberOfWords": { + "message": "I have a $1-word phrase", + "description": "This is the text for each option in the dropdown where a user selects how many words their secret recovery phrase has during import. The $1 is the number of words (either 12, 15, 18, 21, or 24)." + }, + "srpPasteFailedTooManyWords": { + "message": "Paste failed because it contained over 24 words. A secret recovery phrase can have a maximum of 24 words.", + "description": "Description of SRP paste erorr when the pasted content has too many words" + }, + "srpPasteTip": { + "message": "You can paste your entire secret recovery phrase into any field", + "description": "Our secret recovery phrase input is split into one field per word. This message explains to users that they can paste their entire secrete recovery phrase into any field, and we will handle it correctly." + }, + "srpToggleShow": { + "message": "Show/Hide this word of the secret recovery phrase", + "description": "Describes a toggle that is used to show or hide a single word of the secret recovery phrase" + }, + "srpWordHidden": { + "message": "This word is hidden", + "description": "Explains that a word in the secret recovery phrase is hidden" + }, + "srpWordShown": { + "message": "This word is being shown", + "description": "Explains that a word in the secret recovery phrase is being shown" + }, "stable": { "message": "Stable" }, diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json index a08ff6118..0ce491da5 100644 --- a/app/_locales/es/messages.json +++ b/app/_locales/es/messages.json @@ -1520,12 +1520,6 @@ "seedPhraseIntroTitleCopy": { "message": "Antes de comenzar, mire este breve video para aprender sobre su frase de recuperación y sobre cómo mantener segura su cartera." }, - "seedPhrasePlaceholder": { - "message": "Separar cada palabra con un solo espacio" - }, - "seedPhrasePlaceholderPaste": { - "message": "Pegar la frase secreta de recuperación desde el Portapapeles" - }, "seedPhraseReq": { "message": "Las frases secretas de recuperación contienen 12, 15, 18, 21 o 24 palabras" }, @@ -1605,9 +1599,6 @@ "showPrivateKeys": { "message": "Mostrar claves privadas" }, - "showSeedPhrase": { - "message": "Mostrar frase secreta de recuperación" - }, "sigRequest": { "message": "Solicitud de firma" }, diff --git a/app/_locales/es_419/messages.json b/app/_locales/es_419/messages.json index a154558d3..bb9858c3f 100644 --- a/app/_locales/es_419/messages.json +++ b/app/_locales/es_419/messages.json @@ -2392,12 +2392,6 @@ "seedPhraseIntroTitleCopy": { "message": "Antes de comenzar, mire este breve video para aprender sobre su frase de recuperación y sobre cómo proteger su cartera." }, - "seedPhrasePlaceholder": { - "message": "Separar cada palabra con un solo espacio" - }, - "seedPhrasePlaceholderPaste": { - "message": "Pegar la frase secreta de recuperación desde el Portapapeles" - }, "seedPhraseReq": { "message": "Las frases secretas de recuperación contienen 12, 15, 18, 21 o 24 palabras" }, @@ -2511,9 +2505,6 @@ "showRecommendations": { "message": "Mostrar recomendaciones" }, - "showSeedPhrase": { - "message": "Mostrar frase secreta de recuperación" - }, "showTestnetNetworks": { "message": "Mostrar redes de prueba" }, diff --git a/app/_locales/et/messages.json b/app/_locales/et/messages.json index 8bf5aa8ac..b6f929aab 100644 --- a/app/_locales/et/messages.json +++ b/app/_locales/et/messages.json @@ -806,9 +806,6 @@ "securityAndPrivacy": { "message": "Turvalisus ja privaatsus" }, - "seedPhrasePlaceholder": { - "message": "Eraldage iga sõna ühe tühikuga" - }, "seedPhraseReq": { "message": "Seemnefraasid on 12 sõna pikad" }, diff --git a/app/_locales/fa/messages.json b/app/_locales/fa/messages.json index 32b7c8e48..c4cc6a32c 100644 --- a/app/_locales/fa/messages.json +++ b/app/_locales/fa/messages.json @@ -816,9 +816,6 @@ "securityAndPrivacy": { "message": "امنیت و حریم خصوصی" }, - "seedPhrasePlaceholder": { - "message": "هر کلمه را با یک فاصله واحد جدا سازید" - }, "seedPhraseReq": { "message": "عبارات بازیاب 12 کلمه اند" }, diff --git a/app/_locales/fi/messages.json b/app/_locales/fi/messages.json index 108165b57..3301f21dd 100644 --- a/app/_locales/fi/messages.json +++ b/app/_locales/fi/messages.json @@ -813,9 +813,6 @@ "securityAndPrivacy": { "message": "Turva & yksityisyys" }, - "seedPhrasePlaceholder": { - "message": "Erota kukin sana yhdellä välilyönnillä" - }, "seedPhraseReq": { "message": "Juurilauseet ovat 12 sanan pituisia" }, diff --git a/app/_locales/fil/messages.json b/app/_locales/fil/messages.json index 64695058e..474dcc1b0 100644 --- a/app/_locales/fil/messages.json +++ b/app/_locales/fil/messages.json @@ -734,9 +734,6 @@ "securityAndPrivacy": { "message": "Seguridad at Privacy" }, - "seedPhrasePlaceholder": { - "message": "Paghiwa-hiwalayin ang bawat salita gamit ang isang space" - }, "seedPhraseReq": { "message": "Ang mga seed phrase ay may habang 12 salita" }, diff --git a/app/_locales/fr/messages.json b/app/_locales/fr/messages.json index a311e6ca5..e5cd939f9 100644 --- a/app/_locales/fr/messages.json +++ b/app/_locales/fr/messages.json @@ -2343,12 +2343,6 @@ "seedPhraseIntroTitleCopy": { "message": "Avant de commencer, regardez cette courte vidéo pour vous informer sur votre phrase secrète de récupération et sur la manière de sécuriser votre portefeuille." }, - "seedPhrasePlaceholder": { - "message": "Séparez chaque mot par un espace simple" - }, - "seedPhrasePlaceholderPaste": { - "message": "Collez la Phrase secrète de récupération depuis le presse-papiers" - }, "seedPhraseReq": { "message": "Les phrases secrètes de récupération sont composées de 12, 15, 18, 21 ou 24 mots" }, @@ -2459,9 +2453,6 @@ "showRecommendations": { "message": "Afficher les recommandations" }, - "showSeedPhrase": { - "message": "Afficher la phrase secrète de récupération" - }, "showTestnetNetworks": { "message": "Afficher les réseaux de test" }, diff --git a/app/_locales/he/messages.json b/app/_locales/he/messages.json index 8cfe2edbd..36beece50 100644 --- a/app/_locales/he/messages.json +++ b/app/_locales/he/messages.json @@ -810,9 +810,6 @@ "securityAndPrivacy": { "message": "אבטחה ופרטיות" }, - "seedPhrasePlaceholder": { - "message": "הפרד/י בין המילים ברווח אחד" - }, "seedPhraseReq": { "message": "צירופי גרעין מורכבים מ-12 מילים" }, diff --git a/app/_locales/hi/messages.json b/app/_locales/hi/messages.json index 626d1ae25..8b8531835 100644 --- a/app/_locales/hi/messages.json +++ b/app/_locales/hi/messages.json @@ -2343,12 +2343,6 @@ "seedPhraseIntroTitleCopy": { "message": "शुरुआत करने से पहले, अपने गुप्त रिकवरी फ्रेज और अपने वॉलेट को सुरक्षित रखने के तरीके के बारे में जानने के लिए यह छोटा-सा वीडियो देखें।" }, - "seedPhrasePlaceholder": { - "message": "प्रत्येक शब्द को एक रिक्ति से अलग करें" - }, - "seedPhrasePlaceholderPaste": { - "message": "क्लिपबोर्ड से गुप्त रिकवरी फ्रेज़ को चिपकाएँ" - }, "seedPhraseReq": { "message": "गुप्त रिकवरी फ्रेज में 12, 15, 18, 21 या 24 शब्द होते हैं" }, @@ -2459,9 +2453,6 @@ "showRecommendations": { "message": "अनुशंसा दिखाएं" }, - "showSeedPhrase": { - "message": "गुप्त रिकवरी फ्रेज दिखाएं" - }, "showTestnetNetworks": { "message": "परीक्षण नेटवर्क दिखाएं" }, diff --git a/app/_locales/hr/messages.json b/app/_locales/hr/messages.json index eb3ffefb1..c466cb53c 100644 --- a/app/_locales/hr/messages.json +++ b/app/_locales/hr/messages.json @@ -809,9 +809,6 @@ "securityAndPrivacy": { "message": "Sigurnost i privatnost" }, - "seedPhrasePlaceholder": { - "message": "Odvojite pojedinačne riječi jednim razmakom" - }, "seedPhraseReq": { "message": "Početne rečenice imaju 12 riječi" }, diff --git a/app/_locales/hu/messages.json b/app/_locales/hu/messages.json index ddbde0797..f96e8b911 100644 --- a/app/_locales/hu/messages.json +++ b/app/_locales/hu/messages.json @@ -809,9 +809,6 @@ "securityAndPrivacy": { "message": "Biztonság és adatvédelem" }, - "seedPhrasePlaceholder": { - "message": "A szavakat egy-egy szóközzel válassza el" - }, "seedPhraseReq": { "message": "A seed mondat 12 szóból áll" }, diff --git a/app/_locales/id/messages.json b/app/_locales/id/messages.json index bae413007..a66e1d4d6 100644 --- a/app/_locales/id/messages.json +++ b/app/_locales/id/messages.json @@ -2343,12 +2343,6 @@ "seedPhraseIntroTitleCopy": { "message": "Sebelum memulai, lihat video singkat ini untuk mempelajari tentang Frasa Pemulihan Rahasia Anda dan cara menjaga keamanan dompet Anda." }, - "seedPhrasePlaceholder": { - "message": "Pisahkan setiap kata dengan satu spasi" - }, - "seedPhrasePlaceholderPaste": { - "message": "Tempel Frasa Pemulihan Rahasia dari clipboard" - }, "seedPhraseReq": { "message": "Frasa Pemulihan Rahasia berisi 12, 15, 18, 21, atau 24 kata" }, @@ -2459,9 +2453,6 @@ "showRecommendations": { "message": "Tampilkan Rekomendasi" }, - "showSeedPhrase": { - "message": "Tampilkan Frasa Pemulihan Rahasia" - }, "showTestnetNetworks": { "message": "Tampilkan jaringan pengujian" }, diff --git a/app/_locales/it/messages.json b/app/_locales/it/messages.json index b686b183b..058c26f89 100644 --- a/app/_locales/it/messages.json +++ b/app/_locales/it/messages.json @@ -1216,12 +1216,6 @@ "securityAndPrivacy": { "message": "Sicurezza & Privacy" }, - "seedPhrasePlaceholder": { - "message": "Separa ogni parola con un singolo spazio" - }, - "seedPhrasePlaceholderPaste": { - "message": "Incolla frase seed dagli appunti" - }, "seedPhraseReq": { "message": "le frasi seed sono lunghe 12 parole" }, @@ -1298,9 +1292,6 @@ "showPrivateKeys": { "message": "Mostra Chiave Privata" }, - "showSeedPhrase": { - "message": "Mostra frase seed" - }, "sigRequest": { "message": "Firma Richiesta" }, diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json index e544f3a6b..b59af3082 100644 --- a/app/_locales/ja/messages.json +++ b/app/_locales/ja/messages.json @@ -2343,12 +2343,6 @@ "seedPhraseIntroTitleCopy": { "message": "始める前に、この短いビデオを見て、シークレットリカバリーフレーズとウォレットを安全に保つ方法について確認してください。" }, - "seedPhrasePlaceholder": { - "message": "単語ごとにスペースを1つ置いて分離します" - }, - "seedPhrasePlaceholderPaste": { - "message": "クリップボードからシークレット リカバリー フレーズを貼り付けます" - }, "seedPhraseReq": { "message": "シークレットリカバリーフレーズは、12、15、18、21、24語で構成されます" }, @@ -2459,9 +2453,6 @@ "showRecommendations": { "message": "推奨を表示" }, - "showSeedPhrase": { - "message": "シークレットリカバリーフレーズを表示" - }, "showTestnetNetworks": { "message": "テストネットワークを表示" }, diff --git a/app/_locales/kn/messages.json b/app/_locales/kn/messages.json index e6c557c5c..1c575b4a9 100644 --- a/app/_locales/kn/messages.json +++ b/app/_locales/kn/messages.json @@ -816,9 +816,6 @@ "securityAndPrivacy": { "message": "ಭದ್ರತೆ ಮತ್ತು ಗೌಪ್ಯತೆ" }, - "seedPhrasePlaceholder": { - "message": "ಒಂದು ಸ್ಪೇಸ್ ಮೂಲಕ ಪ್ರತಿ ಪದವನ್ನು ಬೇರ್ಪಡಿಸಿ" - }, "seedPhraseReq": { "message": "ಸೀಡ್ ಫ್ರೇಸ್‌ಗಳು 12 ಪದಗಳಷ್ಟು ದೀರ್ಘವಾಗಿವೆ" }, diff --git a/app/_locales/ko/messages.json b/app/_locales/ko/messages.json index 9814be129..c000290ed 100644 --- a/app/_locales/ko/messages.json +++ b/app/_locales/ko/messages.json @@ -2343,12 +2343,6 @@ "seedPhraseIntroTitleCopy": { "message": "시작하기 전에 이 짧은 동영상을 보고 비밀 복구 구문과 지갑을 안전하게 보호하는 방법에 대해 알아보세요." }, - "seedPhrasePlaceholder": { - "message": "공백 한 칸으로 각 단어를 구분하세요." - }, - "seedPhrasePlaceholderPaste": { - "message": "클립보드에서 비밀 복구 구문 붙여넣기" - }, "seedPhraseReq": { "message": "비밀 복구 구문은 12, 15, 18, 21 또는 24개의 단어로 구성됩니다" }, @@ -2459,9 +2453,6 @@ "showRecommendations": { "message": "추천 보기" }, - "showSeedPhrase": { - "message": "비밀 복구 구문 표시" - }, "showTestnetNetworks": { "message": "테스트 네트워크 보기" }, diff --git a/app/_locales/lt/messages.json b/app/_locales/lt/messages.json index 1a7dd9a51..240a7c198 100644 --- a/app/_locales/lt/messages.json +++ b/app/_locales/lt/messages.json @@ -816,9 +816,6 @@ "securityAndPrivacy": { "message": "Sauga ir privatumas" }, - "seedPhrasePlaceholder": { - "message": "Kiekvieną žodį atskirkite viengubu tarpu" - }, "seedPhraseReq": { "message": "Atkūrimo frazės yra 12 žodžių ilgio" }, diff --git a/app/_locales/lv/messages.json b/app/_locales/lv/messages.json index adf1c19d4..e41892d56 100644 --- a/app/_locales/lv/messages.json +++ b/app/_locales/lv/messages.json @@ -812,9 +812,6 @@ "securityAndPrivacy": { "message": "Drošība un konfidencialitāte" }, - "seedPhrasePlaceholder": { - "message": "Atdaliet katru vārdu ar vienu atstarpi" - }, "seedPhraseReq": { "message": "Atkopšanas frāzes ir 12 vārdus garas" }, diff --git a/app/_locales/ms/messages.json b/app/_locales/ms/messages.json index 0675bc2a5..b62072110 100644 --- a/app/_locales/ms/messages.json +++ b/app/_locales/ms/messages.json @@ -796,9 +796,6 @@ "securityAndPrivacy": { "message": "Keselamatan & Privasi" }, - "seedPhrasePlaceholder": { - "message": "Pisahkan setiap perkataan dengan satu ruang" - }, "seedPhraseReq": { "message": "Frasa benih panjangnya 12 patah perkataan" }, diff --git a/app/_locales/no/messages.json b/app/_locales/no/messages.json index a8bb4af03..2f4f94f53 100644 --- a/app/_locales/no/messages.json +++ b/app/_locales/no/messages.json @@ -800,9 +800,6 @@ "securityAndPrivacy": { "message": "Sikkerhet og personvern" }, - "seedPhrasePlaceholder": { - "message": "Skill hvert ord med ett enkelt mellomrom" - }, "seedPhraseReq": { "message": "Mnemoniske gjenopprettingsfraser består av 12 ord " }, diff --git a/app/_locales/ph/messages.json b/app/_locales/ph/messages.json index c738b5788..be9cafadc 100644 --- a/app/_locales/ph/messages.json +++ b/app/_locales/ph/messages.json @@ -1545,12 +1545,6 @@ "seedPhraseIntroTitleCopy": { "message": "Bago magsimula, panoorin ang maikling video na ito para matuto tungkol sa recovery phrase at kung paano panatilihing ligtas ang iyong wallet." }, - "seedPhrasePlaceholder": { - "message": "Paghiwa-hiwalayin ang bawat salita gamit ang isang space" - }, - "seedPhrasePlaceholderPaste": { - "message": "I-paste ang Secret Recovery Phrase mula sa clipboard" - }, "seedPhraseReq": { "message": "Ang mga Secret Recovery Phrase ay naglalaman ng 12, 15, 18, 21, o 24 na salita" }, @@ -1630,9 +1624,6 @@ "showPrivateKeys": { "message": "Ipakita ang Mga Private Key" }, - "showSeedPhrase": { - "message": "Ipakita ang Secret Recovery Phrase" - }, "sigRequest": { "message": "Request ng Signature" }, diff --git a/app/_locales/pl/messages.json b/app/_locales/pl/messages.json index 43f9ca385..8d5e1019e 100644 --- a/app/_locales/pl/messages.json +++ b/app/_locales/pl/messages.json @@ -810,9 +810,6 @@ "securityAndPrivacy": { "message": "Bezpieczeństwo i prywatność" }, - "seedPhrasePlaceholder": { - "message": "Oddziel słowa pojedynczą spacją" - }, "seedPhraseReq": { "message": "Frazy seed mają 12 słów" }, diff --git a/app/_locales/pt_BR/messages.json b/app/_locales/pt_BR/messages.json index 5d1289040..8b161b3cf 100644 --- a/app/_locales/pt_BR/messages.json +++ b/app/_locales/pt_BR/messages.json @@ -2376,12 +2376,6 @@ "seedPhraseIntroTitleCopy": { "message": "Antes de iniciar, assista a esse vídeo curto para aprender sobre sua Frase de Recuperação Secreta e sobre como manter sua carteira segura." }, - "seedPhrasePlaceholder": { - "message": "Separe cada palavra com um único espaço" - }, - "seedPhrasePlaceholderPaste": { - "message": "Cole a Frase de recuperação secreta da área de transferência" - }, "seedPhraseReq": { "message": "As Frases de Recuperação Secretas contêm 12, 15, 18, 21 ou 24 palavras" }, @@ -2495,9 +2489,6 @@ "showRecommendations": { "message": "Mostrar recomendações" }, - "showSeedPhrase": { - "message": "Mostrar Frase de Recuperação Secreta" - }, "showTestnetNetworks": { "message": "Mostrar redes de teste" }, diff --git a/app/_locales/ro/messages.json b/app/_locales/ro/messages.json index 387fac7bb..06cf6f692 100644 --- a/app/_locales/ro/messages.json +++ b/app/_locales/ro/messages.json @@ -803,9 +803,6 @@ "securityAndPrivacy": { "message": "Securitate și confidențialitate" }, - "seedPhrasePlaceholder": { - "message": "Despărțiți fiecare cuvânt cu un spațiu" - }, "seedPhraseReq": { "message": "Expresiile seed sunt lungi de 12 cuvinte" }, diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json index b2dd593ba..49d76144d 100644 --- a/app/_locales/ru/messages.json +++ b/app/_locales/ru/messages.json @@ -2343,12 +2343,6 @@ "seedPhraseIntroTitleCopy": { "message": "Прежде чем приступить к делу, посмотрите это короткое видео о секретной фразе для восстановления и споособах обезопасить кошелек." }, - "seedPhrasePlaceholder": { - "message": "Отделяйте каждое слово одним пробелом" - }, - "seedPhrasePlaceholderPaste": { - "message": "Вставить секретную фразу восстановления из буфера обмена" - }, "seedPhraseReq": { "message": "Секретные фразы для восстановления содержат 12, 15, 18, 21 или 24 слова" }, @@ -2459,9 +2453,6 @@ "showRecommendations": { "message": "Показать рекомендации" }, - "showSeedPhrase": { - "message": "Показать секретную фразу для восстановления" - }, "showTestnetNetworks": { "message": "Показать тестовые сети" }, diff --git a/app/_locales/sk/messages.json b/app/_locales/sk/messages.json index 396bdf170..0fd6d8bb5 100644 --- a/app/_locales/sk/messages.json +++ b/app/_locales/sk/messages.json @@ -779,9 +779,6 @@ "securityAndPrivacy": { "message": "Bezpečnosť a súkromie" }, - "seedPhrasePlaceholder": { - "message": "Každé slovo oddeľte jednou medzerou" - }, "seedPhraseReq": { "message": "klíčové fráze mají 12 slov" }, diff --git a/app/_locales/sl/messages.json b/app/_locales/sl/messages.json index 490e9ed0c..4ebce0449 100644 --- a/app/_locales/sl/messages.json +++ b/app/_locales/sl/messages.json @@ -804,9 +804,6 @@ "securityAndPrivacy": { "message": "Varnost in zasebnost" }, - "seedPhrasePlaceholder": { - "message": "Vsako besedo ločite z enim presledkom" - }, "seedPhraseReq": { "message": "Seed phrase mora biti dolg 12 besed" }, diff --git a/app/_locales/sr/messages.json b/app/_locales/sr/messages.json index 63a52f898..f37701547 100644 --- a/app/_locales/sr/messages.json +++ b/app/_locales/sr/messages.json @@ -807,9 +807,6 @@ "securityAndPrivacy": { "message": "Bezbednost i privatnost" }, - "seedPhrasePlaceholder": { - "message": "Odvojite svaku reč jednim razmakom" - }, "seedPhraseReq": { "message": "Šifre za oporavak naloga (seed phrases) imaju 12 reči" }, diff --git a/app/_locales/sv/messages.json b/app/_locales/sv/messages.json index c3fa28d56..447dcde42 100644 --- a/app/_locales/sv/messages.json +++ b/app/_locales/sv/messages.json @@ -800,9 +800,6 @@ "securityAndPrivacy": { "message": "Säkerhet och integritet" }, - "seedPhrasePlaceholder": { - "message": "Separera varje ord med ett enda mellanslag." - }, "seedPhraseReq": { "message": "Nyckelfraser är 12 ord långa." }, diff --git a/app/_locales/sw/messages.json b/app/_locales/sw/messages.json index 8c4eb4f27..dc1a61406 100644 --- a/app/_locales/sw/messages.json +++ b/app/_locales/sw/messages.json @@ -794,9 +794,6 @@ "securityAndPrivacy": { "message": "Ulinzi na Faragha" }, - "seedPhrasePlaceholder": { - "message": "Tenganisha kila neno kwa nafasi moja" - }, "seedPhraseReq": { "message": "Virai vianzio vina urefu wa maneno 12" }, diff --git a/app/_locales/tl/messages.json b/app/_locales/tl/messages.json index 64bd5b6fc..b9f400d7e 100644 --- a/app/_locales/tl/messages.json +++ b/app/_locales/tl/messages.json @@ -2343,12 +2343,6 @@ "seedPhraseIntroTitleCopy": { "message": "Bago magsimula, panoorin ang maikling video na ito upang malaman ang tungkol sa iyong Secret Recovery Phrase at paano mapapanatiling ligtas ang wallet mo." }, - "seedPhrasePlaceholder": { - "message": "Paghiwa-hiwalayin ang bawat salita gamit ang espasyo" - }, - "seedPhrasePlaceholderPaste": { - "message": "I-paste ang Secret Recovery Phrase mula sa clipboard" - }, "seedPhraseReq": { "message": "Ang mga Secret Recovery Phrase ay naglalaman ng 12, 15, 18, 21, o 24 na salita" }, @@ -2459,9 +2453,6 @@ "showRecommendations": { "message": "Ipakita ang mga Rekomendasyon" }, - "showSeedPhrase": { - "message": "Ipakita ang Secret Recovery Phrase" - }, "showTestnetNetworks": { "message": "Ipakita ang mga test network" }, diff --git a/app/_locales/tr/messages.json b/app/_locales/tr/messages.json index 1f19939af..9cd734cdc 100644 --- a/app/_locales/tr/messages.json +++ b/app/_locales/tr/messages.json @@ -2343,12 +2343,6 @@ "seedPhraseIntroTitleCopy": { "message": "Başlamadan önce Gizli Kurtarma İfadeniz ve cüzdanınızı nasıl güvende tutacağınız hakkında bilgi edinmek için bu kısa videoyu izleyin." }, - "seedPhrasePlaceholder": { - "message": "Her kelimeyi tek bir boşluk ile ayırın" - }, - "seedPhrasePlaceholderPaste": { - "message": "Hafıza panosundan Gizli Kurtarma İfadesini yapıştır" - }, "seedPhraseReq": { "message": "Gizli Kurtarma İfadeleri 12, 15, 18, 21 veya 24 kelimeden oluşur" }, @@ -2459,9 +2453,6 @@ "showRecommendations": { "message": "Önerileri Göster" }, - "showSeedPhrase": { - "message": "Gizli Kurtarma İfadesini Göster" - }, "showTestnetNetworks": { "message": "Test ağlarını göster" }, diff --git a/app/_locales/uk/messages.json b/app/_locales/uk/messages.json index ed521399c..403cafd28 100644 --- a/app/_locales/uk/messages.json +++ b/app/_locales/uk/messages.json @@ -816,9 +816,6 @@ "securityAndPrivacy": { "message": "Безпека й конфіденційність" }, - "seedPhrasePlaceholder": { - "message": "Відділіть кожне слово одним пробілом" - }, "seedPhraseReq": { "message": "Початкові фрази мають 12 слів" }, diff --git a/app/_locales/vi/messages.json b/app/_locales/vi/messages.json index d3cc6931c..de29ab1d5 100644 --- a/app/_locales/vi/messages.json +++ b/app/_locales/vi/messages.json @@ -2343,12 +2343,6 @@ "seedPhraseIntroTitleCopy": { "message": "Trước khi bắt đầu, hãy xem video ngắn này để tìm hiểu thêm về cụm mật khẩu khôi phục bí mật của bạn và cách bảo vệ ví của bạn." }, - "seedPhrasePlaceholder": { - "message": "Phân tách mỗi từ bằng một dấu cách" - }, - "seedPhrasePlaceholderPaste": { - "message": "Dán Cụm mật khẩu khôi phục bí mật từ khay nhớ tạm" - }, "seedPhraseReq": { "message": "Cụm mật khẩu khôi phục bí mật gồm 12, 15, 18, 21 hoặc 24 từ" }, @@ -2459,9 +2453,6 @@ "showRecommendations": { "message": "Hiển Thị Đề Xuất" }, - "showSeedPhrase": { - "message": "Hiển thị Cụm mật khẩu khôi phục bí mật" - }, "showTestnetNetworks": { "message": "Hiển thị các mạng thử nghiệm" }, diff --git a/app/_locales/zh_CN/messages.json b/app/_locales/zh_CN/messages.json index d9c4aa6ea..943a36afd 100644 --- a/app/_locales/zh_CN/messages.json +++ b/app/_locales/zh_CN/messages.json @@ -2343,12 +2343,6 @@ "seedPhraseIntroTitleCopy": { "message": "在开始之前,观看这个简短的视频来了解您的账户助记词以及如何保护您的钱包安全。" }, - "seedPhrasePlaceholder": { - "message": "用空格分隔每个单词" - }, - "seedPhrasePlaceholderPaste": { - "message": "从剪贴板粘贴账户助记词" - }, "seedPhraseReq": { "message": "账户助记词由 12、15、18、21 或 24 个单词组成" }, @@ -2459,9 +2453,6 @@ "showRecommendations": { "message": "显示建议" }, - "showSeedPhrase": { - "message": "显示账户助记词" - }, "showTestnetNetworks": { "message": "显示测试网络" }, diff --git a/app/_locales/zh_TW/messages.json b/app/_locales/zh_TW/messages.json index ba978532e..b16184e25 100644 --- a/app/_locales/zh_TW/messages.json +++ b/app/_locales/zh_TW/messages.json @@ -798,9 +798,6 @@ "securityAndPrivacy": { "message": "安全&隱私" }, - "seedPhrasePlaceholder": { - "message": "單詞之間請用空白分隔" - }, "seedPhraseReq": { "message": "助憶詞為 12 個詞語" }, diff --git a/app/scripts/controllers/permissions/caveat-mutators.js b/app/scripts/controllers/permissions/caveat-mutators.js index fe61df6df..84f9a0ddb 100644 --- a/app/scripts/controllers/permissions/caveat-mutators.js +++ b/app/scripts/controllers/permissions/caveat-mutators.js @@ -1,4 +1,4 @@ -import { CaveatMutatorOperation } from '@metamask/snap-controllers'; +import { CaveatMutatorOperation } from '@metamask/controllers'; import { CaveatTypes } from '../../../../shared/constants/permissions'; /** diff --git a/app/scripts/controllers/permissions/caveat-mutators.test.js b/app/scripts/controllers/permissions/caveat-mutators.test.js index 93c3d0dad..476b3e1f6 100644 --- a/app/scripts/controllers/permissions/caveat-mutators.test.js +++ b/app/scripts/controllers/permissions/caveat-mutators.test.js @@ -1,4 +1,4 @@ -import { CaveatMutatorOperation } from '@metamask/snap-controllers'; +import { CaveatMutatorOperation } from '@metamask/controllers'; import { CaveatTypes } from '../../../../shared/constants/permissions'; import { CaveatMutatorFactories } from './caveat-mutators'; diff --git a/app/scripts/controllers/permissions/flask/snap-permissions.js b/app/scripts/controllers/permissions/flask/snap-permissions.js index bea6ba7a3..bde8c4c91 100644 --- a/app/scripts/controllers/permissions/flask/snap-permissions.js +++ b/app/scripts/controllers/permissions/flask/snap-permissions.js @@ -1,8 +1,9 @@ +import { endowmentPermissionBuilders } from '@metamask/controllers'; import { restrictedMethodPermissionBuilders, selectHooks, } from '@metamask/rpc-methods'; -import { endowmentPermissionBuilders } from '@metamask/snap-controllers'; +import { ExcludedSnapPermissions } from '../../../../../shared/constants/permissions'; /** * @returns {Record>} All endowment permission @@ -24,9 +25,11 @@ export const buildSnapEndowmentSpecifications = () => export function buildSnapRestrictedMethodSpecifications(hooks) { return Object.values(restrictedMethodPermissionBuilders).reduce( (specifications, { targetKey, specificationBuilder, methodHooks }) => { - specifications[targetKey] = specificationBuilder({ - methodHooks: selectHooks(hooks, methodHooks), - }); + if (!ExcludedSnapPermissions.has(targetKey)) { + specifications[targetKey] = specificationBuilder({ + methodHooks: selectHooks(hooks, methodHooks), + }); + } return specifications; }, {}, diff --git a/app/scripts/controllers/permissions/specifications.js b/app/scripts/controllers/permissions/specifications.js index 201810e54..bab176db2 100644 --- a/app/scripts/controllers/permissions/specifications.js +++ b/app/scripts/controllers/permissions/specifications.js @@ -1,7 +1,4 @@ -import { - constructPermission, - PermissionType, -} from '@metamask/snap-controllers'; +import { constructPermission, PermissionType } from '@metamask/controllers'; import { CaveatTypes, RestrictedMethods, diff --git a/app/scripts/lib/rpc-method-middleware/createMethodMiddleware.js b/app/scripts/lib/rpc-method-middleware/createMethodMiddleware.js index 74587ed73..642fdb1ce 100644 --- a/app/scripts/lib/rpc-method-middleware/createMethodMiddleware.js +++ b/app/scripts/lib/rpc-method-middleware/createMethodMiddleware.js @@ -1,10 +1,10 @@ ///: BEGIN:ONLY_INCLUDE_IN(flask) import { handlers as permittedSnapMethods } from '@metamask/rpc-methods/dist/permitted'; ///: END:ONLY_INCLUDE_IN -import { flatten } from 'lodash'; -import { permissionRpcMethods } from '@metamask/snap-controllers'; +import { permissionRpcMethods } from '@metamask/controllers'; import { selectHooks } from '@metamask/rpc-methods'; import { ethErrors } from 'eth-rpc-errors'; +import { flatten } from 'lodash'; import { UNSUPPORTED_RPC_METHODS } from '../../../../shared/constants/network'; import localHandlers from './handlers'; diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index eb5381a6b..8bb569897 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -589,7 +589,7 @@ export default class MetamaskController extends EventEmitter { this.workerController = new IframeExecutionService({ onError: this.onExecutionEnvironmentError.bind(this), iframeUrl: new URL( - 'https://metamask.github.io/iframe-execution-environment/0.3.1', + 'https://metamask.github.io/iframe-execution-environment/0.4.2', ), messenger: this.controllerMessenger.getRestricted({ name: 'ExecutionService', @@ -607,6 +607,7 @@ export default class MetamaskController extends EventEmitter { `${this.permissionController.name}:getEndowments`, `${this.permissionController.name}:getPermissions`, `${this.permissionController.name}:hasPermission`, + `${this.permissionController.name}:hasPermissions`, `${this.permissionController.name}:requestPermissions`, `${this.permissionController.name}:revokeAllPermissions`, ], diff --git a/development/metamaskbot-build-announce.js b/development/metamaskbot-build-announce.js index 2d09a93d1..8f1a0bece 100755 --- a/development/metamaskbot-build-announce.js +++ b/development/metamaskbot-build-announce.js @@ -3,7 +3,7 @@ const { promises: fs } = require('fs'); const path = require('path'); const fetch = require('node-fetch'); const glob = require('fast-glob'); -const VERSION = require('../dist/chrome/manifest.json').version; // eslint-disable-line import/no-unresolved +const VERSION = require('../package.json').version; const { getHighlights } = require('./highlights'); start().catch(console.error); diff --git a/development/sentry-publish.js b/development/sentry-publish.js index 81fa58790..5a988c65b 100644 --- a/development/sentry-publish.js +++ b/development/sentry-publish.js @@ -1,6 +1,11 @@ #!/usr/bin/env node -const VERSION = require('../dist/chrome/manifest.json').version; // eslint-disable-line import/no-unresolved + +const yargs = require('yargs/yargs'); +const { hideBin } = require('yargs/helpers'); + const { runCommand, runInShell } = require('./lib/run-command'); +const { getVersion } = require('./lib/get-version'); +const { BuildType } = require('./lib/build-type'); start().catch((error) => { console.error(error); @@ -8,34 +13,63 @@ start().catch((error) => { }); async function start() { - if (!process.env.SENTRY_ORG) { - throw new Error('Missing required "SENTRY_ORG" environment variable'); - } else if (!process.env.SENTRY_PROJECT) { - throw new Error('Missing required "SENTRY_PROJECT" environment variable'); - } + const { argv } = yargs(hideBin(process.argv)).usage( + '$0 [options]', + 'Publish a release to Sentry', + (_yargs) => + _yargs + .option('org', { + default: 'metamask', + description: 'The Sentry organization', + type: 'string', + }) + .option('project', { + default: 'metamask', + description: 'The Sentry project to publish', + type: 'string', + }) + .option('build-type', { + default: BuildType.main, + description: 'The MetaMask extension build type', + choices: Object.values(BuildType), + }) + .option('build-version', { + default: 0, + description: 'The MetaMask extension build version', + type: 'number', + }), + ); + + const { buildType, buildVersion, org, project } = argv; + + process.env.SENTRY_ORG = org; + process.env.SENTRY_PROJECT = project; const authWorked = await checkIfAuthWorks(); if (!authWorked) { throw new Error(`Sentry auth failed`); } + + const version = getVersion(buildType, buildVersion); + // check if version exists or not - const versionAlreadyExists = await checkIfVersionExists(); + const versionAlreadyExists = await checkIfVersionExists(version); // abort if versions exists if (versionAlreadyExists) { console.log( - `Version "${VERSION}" already exists on Sentry, skipping version creation`, + `Version "${version}" already exists on Sentry, skipping version creation`, ); } else { // create sentry release - console.log(`creating Sentry release for "${VERSION}"...`); - await runCommand('sentry-cli', ['releases', 'new', VERSION]); + console.log(`creating Sentry release for "${version}"...`); + await runCommand('sentry-cli', ['releases', 'new', version]); console.log( - `removing any existing files from Sentry release "${VERSION}"...`, + `removing any existing files from Sentry release "${version}"...`, ); await runCommand('sentry-cli', [ 'releases', 'files', - VERSION, + version, 'delete', '--all', ]); @@ -43,18 +77,23 @@ async function start() { // check if version has artifacts or not const versionHasArtifacts = - versionAlreadyExists && (await checkIfVersionHasArtifacts()); + versionAlreadyExists && (await checkIfVersionHasArtifacts(version)); if (versionHasArtifacts) { console.log( - `Version "${VERSION}" already has artifacts on Sentry, skipping sourcemap upload`, + `Version "${version}" already has artifacts on Sentry, skipping sourcemap upload`, ); return; } + const additionalUploadArgs = []; + if (buildType !== BuildType.main) { + additionalUploadArgs.push('--dist-directory', `dist-${buildType}`); + } // upload sentry source and sourcemaps await runInShell('./development/sentry-upload-artifacts.sh', [ '--release', - VERSION, + version, + ...additionalUploadArgs, ]); } @@ -64,17 +103,17 @@ async function checkIfAuthWorks() { ); } -async function checkIfVersionExists() { +async function checkIfVersionExists(version) { return await doesNotFail(() => - runCommand('sentry-cli', ['releases', 'info', VERSION]), + runCommand('sentry-cli', ['releases', 'info', version]), ); } -async function checkIfVersionHasArtifacts() { +async function checkIfVersionHasArtifacts(version) { const [artifact] = await runCommand('sentry-cli', [ 'releases', 'files', - VERSION, + version, 'list', ]); // When there's no artifacts, we get a response from the shell like this ['', ''] diff --git a/development/sentry-upload-artifacts.sh b/development/sentry-upload-artifacts.sh index 673e1dd73..9d2fd32b4 100755 --- a/development/sentry-upload-artifacts.sh +++ b/development/sentry-upload-artifacts.sh @@ -23,17 +23,20 @@ Upload JavaScript bundles and sourcemaps to Sentry Options: -h, --help Show help text -r, --release Sentry release to upload files to (defaults to 'VERSION' environment variable) + --dist-directory The 'dist' directory to use. Defaults to 'dist'. EOF } function upload_sourcemaps { local release="${1}"; shift + local dist_directory="${1}"; shift - sentry-cli releases files "${release}" upload-sourcemaps ./dist/chrome/*.js ./dist/sourcemaps/ --rewrite --url-prefix 'metamask' + sentry-cli releases files "${release}" upload-sourcemaps "${dist_directory}"/chrome/*.js "${dist_directory}"/sourcemaps/ --rewrite --url-prefix 'metamask' } function main { local release=VERSION + local dist_directory='dist' while :; do case "${1-default}" in @@ -51,6 +54,16 @@ function main { release="${2}" shift ;; + --dist-directory) + if [[ -z $2 ]] + then + printf "'dist-directory' option requires an argument.\\n" >&2 + printf '%s\n' "${__SEE_HELP_MESSAGE__}" >&2 + exit 1 + fi + dist_directory="${2}" + shift + ;; *) break esac @@ -70,7 +83,7 @@ function main { fi printf 'uploading source files and sourcemaps for Sentry release "%s"...\n' "${release}" - upload_sourcemaps "${release}" + upload_sourcemaps "${release}" "${dist_directory}" printf 'all done!\n' } diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 86a77a3df..96c7162b2 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -695,6 +695,7 @@ }, "@metamask/rpc-methods": { "packages": { + "@metamask/controllers": true, "@metamask/key-tree": true, "@metamask/snap-controllers": true, "eth-rpc-errors": true @@ -734,25 +735,24 @@ "clearTimeout": true, "console.error": true, "console.log": true, - "fetch": true, + "console.warn": true, "setTimeout": true }, "packages": { "@metamask/controllers": true, + "@metamask/execution-environments": true, "@metamask/object-multiplex": true, "@metamask/obs-store": true, "@metamask/post-message-stream": true, "@metamask/safe-event-emitter": true, - "@metamask/snap-workers": true, "ajv": true, "buffer": true, "concat-stream": true, + "cross-fetch": true, "crypto-browserify": true, - "deep-freeze-strict": true, "eth-rpc-errors": true, "fast-deep-equal": true, "gunzip-maybe": true, - "immer": true, "json-rpc-engine": true, "json-rpc-middleware-stream": true, "nanoid": true, diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index 9882d00ed..c86c0b485 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -630,16 +630,15 @@ "@metamask/iframe-execution-environment-service": { "globals": { "clearTimeout": true, - "console.log": true, "document.body.appendChild": true, "document.createElement": true, "document.getElementById": true, "setTimeout": true }, "packages": { + "@metamask/execution-environments": true, "@metamask/post-message-stream": true, "@metamask/snap-controllers": true, - "@metamask/snap-workers": true, "json-rpc-engine": true, "json-rpc-middleware-stream": true, "nanoid": true, @@ -714,6 +713,7 @@ }, "@metamask/rpc-methods": { "packages": { + "@metamask/controllers": true, "@metamask/key-tree": true, "@metamask/snap-controllers": true, "eth-rpc-errors": true @@ -753,25 +753,24 @@ "clearTimeout": true, "console.error": true, "console.log": true, - "fetch": true, + "console.warn": true, "setTimeout": true }, "packages": { "@metamask/controllers": true, + "@metamask/execution-environments": true, "@metamask/object-multiplex": true, "@metamask/obs-store": true, "@metamask/post-message-stream": true, "@metamask/safe-event-emitter": true, - "@metamask/snap-workers": true, "ajv": true, "buffer": true, "concat-stream": true, + "cross-fetch": true, "crypto-browserify": true, - "deep-freeze-strict": true, "eth-rpc-errors": true, "fast-deep-equal": true, "gunzip-maybe": true, - "immer": true, "json-rpc-engine": true, "json-rpc-middleware-stream": true, "nanoid": true, diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 86a77a3df..96c7162b2 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -695,6 +695,7 @@ }, "@metamask/rpc-methods": { "packages": { + "@metamask/controllers": true, "@metamask/key-tree": true, "@metamask/snap-controllers": true, "eth-rpc-errors": true @@ -734,25 +735,24 @@ "clearTimeout": true, "console.error": true, "console.log": true, - "fetch": true, + "console.warn": true, "setTimeout": true }, "packages": { "@metamask/controllers": true, + "@metamask/execution-environments": true, "@metamask/object-multiplex": true, "@metamask/obs-store": true, "@metamask/post-message-stream": true, "@metamask/safe-event-emitter": true, - "@metamask/snap-workers": true, "ajv": true, "buffer": true, "concat-stream": true, + "cross-fetch": true, "crypto-browserify": true, - "deep-freeze-strict": true, "eth-rpc-errors": true, "fast-deep-equal": true, "gunzip-maybe": true, - "immer": true, "json-rpc-engine": true, "json-rpc-middleware-stream": true, "nanoid": true, diff --git a/package.json b/package.json index 12e5221b6..8d4802c79 100644 --- a/package.json +++ b/package.json @@ -86,8 +86,8 @@ "3box/ipfs/ipld-zcash/zcash-bitcore-lib/elliptic": "^6.5.4", "3box/ipfs/libp2p-mdns/multicast-dns/dns-packet": "^5.2.2", "3box/ipfs/prometheus-gc-stats/gc-stats/node-pre-gyp/tar": "^6.1.2", - "3box/**/libp2p-crypto/node-forge": "^1.0.0", - "3box/**/libp2p-keychain/node-forge": "^1.0.0", + "3box/**/libp2p-crypto/node-forge": "^1.3.0", + "3box/**/libp2p-keychain/node-forge": "^1.3.0", "3box/ipfs/libp2p-webrtc-star/socket.io/engine.io": "^4.0.0", "analytics-node/axios": "^0.21.2", "ganache-core/lodash": "^4.17.21", @@ -112,21 +112,21 @@ "@keystonehq/metamask-airgapped-keyring": "0.2.1", "@material-ui/core": "^4.11.0", "@metamask/contract-metadata": "^1.31.0", - "@metamask/controllers": "^26.0.0", "@metamask/design-tokens": "^1.3.0", + "@metamask/controllers": "^27.0.0", "@metamask/eth-ledger-bridge-keyring": "^0.10.0", "@metamask/eth-token-tracker": "^4.0.0", "@metamask/etherscan-link": "^2.1.0", - "@metamask/iframe-execution-environment-service": "^0.9.0", + "@metamask/iframe-execution-environment-service": "^0.10.6", "@metamask/jazzicon": "^2.0.0", "@metamask/logo": "^3.1.1", "@metamask/obs-store": "^5.0.0", "@metamask/post-message-stream": "^4.0.0", "@metamask/providers": "^8.1.1", - "@metamask/rpc-methods": "^0.9.0", + "@metamask/rpc-methods": "^0.10.6", "@metamask/slip44": "^2.0.0", "@metamask/smart-transactions-controller": "^1.9.1", - "@metamask/snap-controllers": "^0.9.0", + "@metamask/snap-controllers": "^0.10.6", "@ngraveio/bc-ur": "^1.1.6", "@popperjs/core": "^2.4.0", "@reduxjs/toolkit": "^1.6.2", @@ -423,7 +423,11 @@ "ganache>leveldown": false, "geckodriver": true, "react-devtools>electron": true, - "eth-trezor-keyring>trezor-connect>@trezor/transport>protobufjs": false + "eth-trezor-keyring>trezor-connect>@trezor/transport>protobufjs": false, + "@metamask/iframe-execution-environment-service>@metamask/execution-environments": false, + "@metamask/snap-controllers>@metamask/execution-environments": false, + "@metamask/iframe-execution-environment-service>@metamask/snap-controllers>@metamask/execution-environments": false, + "@metamask/rpc-methods>@metamask/snap-controllers>@metamask/execution-environments": false } } } diff --git a/shared/constants/permissions.js b/shared/constants/permissions.js index ddfb12e23..982f20e7b 100644 --- a/shared/constants/permissions.js +++ b/shared/constants/permissions.js @@ -21,4 +21,7 @@ export const PermissionNamespaces = Object.freeze({ export const EndowmentPermissions = Object.freeze({ 'endowment:network-access': 'endowment:network-access', }); + +// Methods / permissions in external packages that we are temporarily excluding. +export const ExcludedSnapPermissions = new Set(['snap_notify']); ///: END:ONLY_INCLUDE_IN diff --git a/shared/constants/permissions.test.js b/shared/constants/permissions.test.js index 2c3b408f0..c6ace6243 100644 --- a/shared/constants/permissions.test.js +++ b/shared/constants/permissions.test.js @@ -1,6 +1,10 @@ -import { endowmentPermissionBuilders } from '@metamask/snap-controllers'; +import { endowmentPermissionBuilders } from '@metamask/controllers'; import { restrictedMethodPermissionBuilders } from '@metamask/rpc-methods'; -import { EndowmentPermissions, RestrictedMethods } from './permissions'; +import { + EndowmentPermissions, + ExcludedSnapPermissions, + RestrictedMethods, +} from './permissions'; describe('EndowmentPermissions', () => { it('has the expected permission keys', () => { @@ -15,7 +19,9 @@ describe('RestrictedMethods', () => { expect(Object.keys(RestrictedMethods).sort()).toStrictEqual( [ 'eth_accounts', - ...Object.keys(restrictedMethodPermissionBuilders), + ...Object.keys(restrictedMethodPermissionBuilders).filter( + (targetKey) => !ExcludedSnapPermissions.has(targetKey), + ), ].sort(), ); }); diff --git a/test/e2e/helpers.js b/test/e2e/helpers.js index 3d8e46f4a..8b251adf7 100644 --- a/test/e2e/helpers.js +++ b/test/e2e/helpers.js @@ -248,8 +248,8 @@ const completeImportSRPOnboardingFlow = async ( await driver.clickElement('.btn-secondary'); // Import Secret Recovery Phrase - await driver.fill( - 'input[placeholder="Enter your Secret Recovery Phrase"]', + await driver.pasteIntoField( + '[data-testid="import-srp__srp-word-0"]', seedPhrase, ); diff --git a/test/e2e/metamask-ui.spec.js b/test/e2e/metamask-ui.spec.js index 30ca8d43b..f80d737f8 100644 --- a/test/e2e/metamask-ui.spec.js +++ b/test/e2e/metamask-ui.spec.js @@ -202,11 +202,10 @@ describe('MetaMask', function () { await restoreSeedLink.click(); await driver.delay(regularDelayMs); - await driver.fill( - 'input[placeholder="Enter your Secret Recovery Phrase"]', + await driver.pasteIntoField( + '[data-testid="import-srp__srp-word-0"]', testSeedPhrase, ); - await driver.delay(regularDelayMs); await driver.fill('#password', 'correct horse battery staple'); await driver.fill('#confirm-password', 'correct horse battery staple'); diff --git a/test/e2e/tests/add-account.spec.js b/test/e2e/tests/add-account.spec.js index 5c0d3fcb9..9d15d76f3 100644 --- a/test/e2e/tests/add-account.spec.js +++ b/test/e2e/tests/add-account.spec.js @@ -129,8 +129,8 @@ describe('Add account', function () { await restoreSeedLink.click(); await driver.delay(regularDelayMs); - await driver.fill( - 'input[placeholder="Enter your Secret Recovery Phrase"]', + await driver.pasteIntoField( + '[data-testid="import-srp__srp-word-0"]', testSeedPhrase, ); await driver.delay(regularDelayMs); diff --git a/test/e2e/tests/metamask-responsive-ui.spec.js b/test/e2e/tests/metamask-responsive-ui.spec.js index e01e5b307..8daa2024f 100644 --- a/test/e2e/tests/metamask-responsive-ui.spec.js +++ b/test/e2e/tests/metamask-responsive-ui.spec.js @@ -169,8 +169,8 @@ describe('Metamask Responsive UI', function () { assert.equal(await restoreSeedLink.getText(), 'Forgot password?'); await restoreSeedLink.click(); - await driver.fill( - 'input[placeholder="Enter your Secret Recovery Phrase"]', + await driver.pasteIntoField( + '[data-testid="import-srp__srp-word-0"]', testSeedPhrase, ); diff --git a/test/e2e/webdriver/driver.js b/test/e2e/webdriver/driver.js index 84342ae69..8f23f3cdc 100644 --- a/test/e2e/webdriver/driver.js +++ b/test/e2e/webdriver/driver.js @@ -1,6 +1,6 @@ const { promises: fs } = require('fs'); const { strict: assert } = require('assert'); -const { until, error: webdriverError, By } = require('selenium-webdriver'); +const { until, error: webdriverError, By, Key } = require('selenium-webdriver'); const cssToXPath = require('css-to-xpath'); /** @@ -257,6 +257,26 @@ class Driver { } } + /** + * Paste a string into a field. + * + * @param {string} element - The element locator. + * @param {string} contentToPaste - The content to paste. + */ + async pasteIntoField(element, contentToPaste) { + // Throw if double-quote is present in content to paste + // so that we don't have to worry about escaping double-quotes + if (contentToPaste.includes('"')) { + throw new Error('Cannot paste content with double-quote'); + } + // Click to focus the field + await this.clickElement(element); + await this.executeScript( + `navigator.clipboard.writeText("${contentToPaste}")`, + ); + await this.fill(element, Key.chord(Key.CONTROL, 'v')); + } + // Navigation async navigate(page = Driver.PAGES.HOME) { diff --git a/ui/components/app/create-new-vault/create-new-vault.js b/ui/components/app/create-new-vault/create-new-vault.js index 05ca7a716..9fef846f4 100644 --- a/ui/components/app/create-new-vault/create-new-vault.js +++ b/ui/components/app/create-new-vault/create-new-vault.js @@ -107,31 +107,31 @@ export default function CreateNewVault({ return (
-
- + +
+ onPasswordChange(event.target.value)} + error={passwordError} + autoComplete="new-password" + margin="normal" + largeLabel + /> + onConfirmPasswordChange(event.target.value)} + error={confirmPasswordError} + autoComplete="new-password" + margin="normal" + largeLabel + />
- onPasswordChange(event.target.value)} - error={passwordError} - autoComplete="new-password" - margin="normal" - largeLabel - /> - onConfirmPasswordChange(event.target.value)} - error={confirmPasswordError} - autoComplete="new-password" - margin="normal" - largeLabel - /> {includeTerms ? (
- v {version} + {t('shorthandVersion', [version])} )} diff --git a/ui/components/app/permission-page-container/index.scss b/ui/components/app/permission-page-container/index.scss index aaf2753bd..5a087b18c 100644 --- a/ui/components/app/permission-page-container/index.scss +++ b/ui/components/app/permission-page-container/index.scss @@ -53,6 +53,7 @@ } &__requested { + width: 100%; text-align: left; } @@ -91,6 +92,7 @@ } &__permissions-container { + width: 100%; display: flex; flex-direction: column; margin-top: 38px; diff --git a/ui/components/app/permissions-connect-header/permissions-connect-header.component.js b/ui/components/app/permissions-connect-header/permissions-connect-header.component.js index 33dc5f3b8..c5ddf0110 100644 --- a/ui/components/app/permissions-connect-header/permissions-connect-header.component.js +++ b/ui/components/app/permissions-connect-header/permissions-connect-header.component.js @@ -5,12 +5,24 @@ import Box from '../../ui/box'; import { FLEX_DIRECTION, JUSTIFY_CONTENT, + ///: BEGIN:ONLY_INCLUDE_IN(flask) + COLORS, + TYPOGRAPHY, + TEXT_ALIGN, + ///: END:ONLY_INCLUDE_IN } from '../../../helpers/constants/design-system'; ///: BEGIN:ONLY_INCLUDE_IN(flask) import SnapsAuthorshipPill from '../flask/snaps-authorship-pill'; +import Typography from '../../ui/typography'; ///: END:ONLY_INCLUDE_IN export default class PermissionsConnectHeader extends Component { + ///: BEGIN:ONLY_INCLUDE_IN(flask) + static contextTypes = { + t: PropTypes.func, + }; + ///: END:ONLY_INCLUDE_IN + static propTypes = { iconUrl: PropTypes.string, iconName: PropTypes.string.isRequired, @@ -20,6 +32,7 @@ export default class PermissionsConnectHeader extends Component { headerText: PropTypes.string, ///: BEGIN:ONLY_INCLUDE_IN(flask) npmPackageName: PropTypes.string, + snapVersion: PropTypes.string, ///: END:ONLY_INCLUDE_IN }; @@ -47,10 +60,12 @@ export default class PermissionsConnectHeader extends Component { headerText, ///: BEGIN:ONLY_INCLUDE_IN(flask) npmPackageName, + snapVersion, ///: END:ONLY_INCLUDE_IN } = this.props; ///: BEGIN:ONLY_INCLUDE_IN(flask) const npmPackageUrl = `https://www.npmjs.com/package/${npmPackageName}`; + const { t } = this.context; ///: END:ONLY_INCLUDE_IN return ( + {t('shorthandVersion', [snapVersion])} + + ) + ///: END:ONLY_INCLUDE_IN + }
{headerText}
); diff --git a/ui/components/app/permissions-connect-permission-list/index.scss b/ui/components/app/permissions-connect-permission-list/index.scss index adbe224b7..17be8eda6 100644 --- a/ui/components/app/permissions-connect-permission-list/index.scss +++ b/ui/components/app/permissions-connect-permission-list/index.scss @@ -1,7 +1,10 @@ .permissions-connect-permission-list { + width: 100%; + .permission { @include H6; + width: 100%; padding-bottom: 16px; border-bottom: 1px solid var(--Grey-100); display: flex; diff --git a/ui/components/app/srp-input/srp-input.js b/ui/components/app/srp-input/srp-input.js index 0192ba1b8..436df3644 100644 --- a/ui/components/app/srp-input/srp-input.js +++ b/ui/components/app/srp-input/srp-input.js @@ -4,96 +4,219 @@ import PropTypes from 'prop-types'; import { useI18nContext } from '../../../hooks/useI18nContext'; import TextField from '../../ui/text-field'; import { clearClipboard } from '../../../helpers/utils/util'; -import CheckBox from '../../ui/check-box'; +import ActionableMessage from '../../ui/actionable-message'; +import Dropdown from '../../ui/dropdown'; import Typography from '../../ui/typography'; -import { COLORS } from '../../../helpers/constants/design-system'; +import ShowHideToggle from '../../ui/show-hide-toggle'; +import { TYPOGRAPHY } from '../../../helpers/constants/design-system'; import { parseSecretRecoveryPhrase } from './parse-secret-recovery-phrase'; const { isValidMnemonic } = ethers.utils; +const defaultNumberOfWords = 12; + export default function SrpInput({ onChange }) { const [srpError, setSrpError] = useState(''); - const [draftSrp, setDraftSrp] = useState(''); - const [showSrp, setShowSrp] = useState(false); + const [pasteFailed, setPasteFailed] = useState(false); + const [draftSrp, setDraftSrp] = useState( + new Array(defaultNumberOfWords).fill(''), + ); + const [showSrp, setShowSrp] = useState( + new Array(defaultNumberOfWords).fill(false), + ); + const [numberOfWords, setNumberOfWords] = useState(defaultNumberOfWords); const t = useI18nContext(); const onSrpChange = useCallback( - (event) => { - const rawSrp = event.target.value; + (newDraftSrp) => { let newSrpError = ''; - const parsedSeedPhrase = parseSecretRecoveryPhrase(rawSrp); + const joinedDraftSrp = newDraftSrp.join(' '); - if (rawSrp) { - const wordCount = parsedSeedPhrase.split(/\s/u).length; - if (wordCount % 3 !== 0 || wordCount > 24 || wordCount < 12) { + if (newDraftSrp.some((word) => word !== '')) { + if (newDraftSrp.some((word) => word === '')) { newSrpError = t('seedPhraseReq'); - } else if (!isValidMnemonic(parsedSeedPhrase)) { + } else if (!isValidMnemonic(joinedDraftSrp)) { newSrpError = t('invalidSeedPhrase'); } } - setDraftSrp(rawSrp); + setDraftSrp(newDraftSrp); setSrpError(newSrpError); - onChange(newSrpError ? '' : parsedSeedPhrase); + onChange(newSrpError ? '' : joinedDraftSrp); }, [setDraftSrp, setSrpError, t, onChange], ); - const toggleShowSrp = useCallback(() => { - setShowSrp((currentShowSrp) => !currentShowSrp); + const toggleShowSrp = useCallback((index) => { + setShowSrp((currentShowSrp) => { + const newShowSrp = currentShowSrp.slice(); + if (newShowSrp[index]) { + newShowSrp[index] = false; + } else { + newShowSrp.fill(false); + newShowSrp[index] = true; + } + return newShowSrp; + }); }, []); + const onSrpWordChange = useCallback( + (index, newWord) => { + if (pasteFailed) { + setPasteFailed(false); + } + const newSrp = draftSrp.slice(); + newSrp[index] = newWord.trim(); + onSrpChange(newSrp); + }, + [draftSrp, onSrpChange, pasteFailed], + ); + + const onSrpPaste = useCallback( + (rawSrp) => { + const parsedSrp = parseSecretRecoveryPhrase(rawSrp); + let newDraftSrp = parsedSrp.split(' '); + + if (newDraftSrp.length > 24) { + setPasteFailed(true); + return; + } else if (pasteFailed) { + setPasteFailed(false); + } + + let newNumberOfWords = numberOfWords; + if (newDraftSrp.length !== numberOfWords) { + if (newDraftSrp.length < 12) { + newNumberOfWords = 12; + } else if (newDraftSrp.length % 3 === 0) { + newNumberOfWords = newDraftSrp.length; + } else { + newNumberOfWords = + newDraftSrp.length + (3 - (newDraftSrp.length % 3)); + } + setNumberOfWords(newNumberOfWords); + } + + if (newDraftSrp.length < newNumberOfWords) { + newDraftSrp = newDraftSrp.concat( + new Array(newNumberOfWords - newDraftSrp.length).fill(''), + ); + } + setShowSrp(new Array(newNumberOfWords).fill(false)); + onSrpChange(newDraftSrp); + clearClipboard(); + }, + [numberOfWords, onSrpChange, pasteFailed, setPasteFailed], + ); + + const numberOfWordsOptions = []; + for (let i = 12; i <= 24; i += 3) { + numberOfWordsOptions.push({ + name: t('srpInputNumberOfWords', [`${i}`]), + value: `${i}`, + }); + } + return ( - <> -