diff --git a/app/soapbox/actions/auth.js b/app/soapbox/actions/auth.js index a8d6d5f0fc..8beb9c1eb5 100644 Binary files a/app/soapbox/actions/auth.js and b/app/soapbox/actions/auth.js differ diff --git a/app/soapbox/actions/mfa.js b/app/soapbox/actions/mfa.js new file mode 100644 index 0000000000..0a8a706ebc Binary files /dev/null and b/app/soapbox/actions/mfa.js differ diff --git a/app/soapbox/actions/settings.js b/app/soapbox/actions/settings.js index 0c2f35a8b7..a482b519cf 100644 Binary files a/app/soapbox/actions/settings.js and b/app/soapbox/actions/settings.js differ diff --git a/app/soapbox/features/auth_login/components/__tests__/__snapshots__/login_form-test.js.snap b/app/soapbox/features/auth_login/components/__tests__/__snapshots__/login_form-test.js.snap index 6c34feba79..646a96d498 100644 --- a/app/soapbox/features/auth_login/components/__tests__/__snapshots__/login_form-test.js.snap +++ b/app/soapbox/features/auth_login/components/__tests__/__snapshots__/login_form-test.js.snap @@ -3,11 +3,8 @@ exports[` renders correctly 1`] = `
-
+
diff --git a/app/soapbox/features/auth_login/components/__tests__/__snapshots__/login_page-test.js.snap b/app/soapbox/features/auth_login/components/__tests__/__snapshots__/login_page-test.js.snap index 35adf1d297..69885fe7bc 100644 --- a/app/soapbox/features/auth_login/components/__tests__/__snapshots__/login_page-test.js.snap +++ b/app/soapbox/features/auth_login/components/__tests__/__snapshots__/login_page-test.js.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[` renders correctly 1`] = ` +exports[` renders correctly on load 1`] = ` renders correctly 1`] = ` `; -exports[` renders correctly 2`] = `null`; +exports[` renders correctly on load 2`] = `null`; diff --git a/app/soapbox/features/auth_login/components/__tests__/login_page-test.js b/app/soapbox/features/auth_login/components/__tests__/login_page-test.js index f0e3d7901c..27393c6c31 100644 Binary files a/app/soapbox/features/auth_login/components/__tests__/login_page-test.js and b/app/soapbox/features/auth_login/components/__tests__/login_page-test.js differ diff --git a/app/soapbox/features/auth_login/components/__tests__/otp_auth_form-test.js b/app/soapbox/features/auth_login/components/__tests__/otp_auth_form-test.js new file mode 100644 index 0000000000..799a5e8199 Binary files /dev/null and b/app/soapbox/features/auth_login/components/__tests__/otp_auth_form-test.js differ diff --git a/app/soapbox/features/auth_login/components/login_form.js b/app/soapbox/features/auth_login/components/login_form.js index 1b669063b1..0a964f4492 100644 Binary files a/app/soapbox/features/auth_login/components/login_form.js and b/app/soapbox/features/auth_login/components/login_form.js differ diff --git a/app/soapbox/features/auth_login/components/login_page.js b/app/soapbox/features/auth_login/components/login_page.js index 2de7daa8f5..934ce12ea7 100644 Binary files a/app/soapbox/features/auth_login/components/login_page.js and b/app/soapbox/features/auth_login/components/login_page.js differ diff --git a/app/soapbox/features/auth_login/components/otp_auth_form.js b/app/soapbox/features/auth_login/components/otp_auth_form.js new file mode 100644 index 0000000000..21655f4929 Binary files /dev/null and b/app/soapbox/features/auth_login/components/otp_auth_form.js differ diff --git a/app/soapbox/features/public_layout/components/header.js b/app/soapbox/features/public_layout/components/header.js index 9f018cc3cf..70c20dcaaa 100644 Binary files a/app/soapbox/features/public_layout/components/header.js and b/app/soapbox/features/public_layout/components/header.js differ diff --git a/app/soapbox/features/security/index.js b/app/soapbox/features/security/index.js index f69c31f6d1..b13305dd15 100644 Binary files a/app/soapbox/features/security/index.js and b/app/soapbox/features/security/index.js differ diff --git a/app/soapbox/features/security/mfa_form.js b/app/soapbox/features/security/mfa_form.js new file mode 100644 index 0000000000..572579d530 Binary files /dev/null and b/app/soapbox/features/security/mfa_form.js differ diff --git a/app/soapbox/features/ui/index.js b/app/soapbox/features/ui/index.js index 7ca9f788f8..f4a4be4138 100644 Binary files a/app/soapbox/features/ui/index.js and b/app/soapbox/features/ui/index.js differ diff --git a/app/soapbox/features/ui/util/async-components.js b/app/soapbox/features/ui/util/async-components.js index 48f36a954c..e6c468ea06 100644 Binary files a/app/soapbox/features/ui/util/async-components.js and b/app/soapbox/features/ui/util/async-components.js differ diff --git a/app/styles/about.scss b/app/styles/about.scss index 27a02f0119..77d93917e4 100644 --- a/app/styles/about.scss +++ b/app/styles/about.scss @@ -34,6 +34,7 @@ $small-breakpoint: 960px; flex-wrap: nowrap; padding: 14px 0; box-sizing: border-box; + position: relative; @media screen and (max-width: 1024px) { padding: 14px 20px; @@ -1712,7 +1713,40 @@ $small-breakpoint: 960px; .header, .container { position: relative; - z-index: 1; + } + + .otp-form-overlay__container { + z-index: 9998; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + display: flex; + align-items: center; + justify-content: center; + background: rgba($base-overlay-background, 0.7); + + .otp-form-overlay__form { + @include standard-panel-shadow; + border-radius: 10px; + z-index: 9999; + margin: 0 auto; + max-width: 800px; + position: relative; + padding: 20px; + background-color: var(--background-color); + display: flex; + flex-direction: column; + + .simple_form { + padding: 30px 50px 50px; + } + + .otp-form-overlay__close { + align-self: flex-end; + } + } } } @@ -1725,3 +1759,10 @@ $small-breakpoint: 960px; bottom: 0; right: 0; } + +h1.otp-login { + font-size: 16px; + line-height: 24px; + font-weight: 800; + padding: 10px 0; +} diff --git a/app/styles/application.scss b/app/styles/application.scss index b040685c9e..dee4df0ba6 100644 --- a/app/styles/application.scss +++ b/app/styles/application.scss @@ -72,3 +72,4 @@ @import 'components/video-player'; @import 'components/audio-player'; @import 'components/profile_hover_card'; +@import 'components/mfa_form'; diff --git a/app/styles/components/buttons.scss b/app/styles/components/buttons.scss index fd664d06dc..49070ad6ca 100644 --- a/app/styles/components/buttons.scss +++ b/app/styles/components/buttons.scss @@ -102,7 +102,7 @@ button { &:focus, &:hover { border-color: var(--brand-color); - color: var(--primary-text-color); + color: var(--background-color); } &:disabled { diff --git a/app/styles/components/mfa_form.scss b/app/styles/components/mfa_form.scss new file mode 100644 index 0000000000..80e16da1eb --- /dev/null +++ b/app/styles/components/mfa_form.scss @@ -0,0 +1,81 @@ +.security-settings-panel { + margin: 20px; + + h1.security-settings-panel__setup-otp { + font-size: 20px; + line-height: 1.25; + color: var(--primary-text-color); + font-weight: 600; + } + + h2.security-settings-panel__setup-otp { + display: block; + font-size: 16px; + line-height: 1.5; + color: var(--primary-text-color--faint); + font-weight: 400; + } + + div { + display: block; + margin: 10px 0; + } + + .security-warning { + color: var(--primary-text-color); + padding: 15px 20px; + font-size: 14px; + background-color: var(--warning-color--faint); + margin: 5px 20px; + border-radius: 8px; + margin: 20px auto; + } + + .backup_codes { + margin: 20px; + font-weight: bold; + padding: 15px 20px; + font-size: 14px; + background-color: var(--brand-color--faint); + border-radius: 8px; + margin: 20px; + text-align: center; + position: relative; + min-height: 125px; + + .backup_code { + margin: 5px auto; + } + + .loading-indicator { + position: absolute; + } + } + + .security-settings-panel__setup-otp__buttons { + margin: 20px; + display: flex; + justify-content: space-between; + + .button { + min-width: 182px; + } + } + + div.confirm-key { + display: block; + font-size: 16px; + line-height: 1.5; + color: var(--primary-text-color--faint); + font-weight: 400; + margin: 0 0 20px 20px; + } +} + +form.otp-auth { + .error-box { + width: 100%; + text-align: center; + color: $error-red; + } +} diff --git a/app/styles/components/tabs-bar.scss b/app/styles/components/tabs-bar.scss index 02dac4e2b8..76920534b3 100644 --- a/app/styles/components/tabs-bar.scss +++ b/app/styles/components/tabs-bar.scss @@ -255,9 +255,9 @@ display: block; margin-right: 30px; border: 0; - height: 50px; + height: 40px; overflow: hidden; - padding: 10px 0; + padding: 13px 0 0; box-sizing: border-box; filter: brightness(0%) grayscale(100%) invert(100%); & span {display: none !important;} diff --git a/app/styles/themes.scss b/app/styles/themes.scss index 1a717e2436..13d952b17a 100644 --- a/app/styles/themes.scss +++ b/app/styles/themes.scss @@ -30,12 +30,14 @@ body { --accent-color: hsl(var(--accent-color_hsl)); --primary-text-color: hsl(var(--primary-text-color_hsl)); --background-color: hsl(var(--background-color_hsl)); + --warning-color: hsla(var(--warning-color_hsl)); // Meta-variables --brand-color_hsl: var(--brand-color_h), var(--brand-color_s), var(--brand-color_l); --accent-color_hsl: var(--accent-color_h), var(--accent-color_s), var(--accent-color_l); --primary-text-color_hsl: var(--primary-text-color_h), var(--primary-text-color_s), var(--primary-text-color_l); --background-color_hsl: var(--background-color_h), var(--background-color_s), var(--background-color_l); + --warning-color_hsl: var(--warning-color_h), var(--warning-color_s), var(--warning-color_l); --accent-color_h: calc(var(--brand-color_h) - 15); --accent-color_s: 86%; --accent-color_l: 44%; @@ -51,6 +53,7 @@ body { calc(var(--accent-color_l) + 3%) ); --primary-text-color--faint: hsla(var(--primary-text-color_hsl), 0.6); + --warning-color--faint: hsla(var(--warning-color_hsl), 0.5); } body.theme-mode-light { @@ -69,6 +72,9 @@ body.theme-mode-light { --background-color_h: 0; --background-color_s: 0%; --background-color_l: 94.9%; + --warning-color_h: 0; + --warning-color_s: 100%; + --warning-color_l: 66%; // Modifiers --brand-color--hicontrast: hsl( @@ -94,6 +100,9 @@ body.theme-mode-dark { --background-color_h: 0; --background-color_s: 0%; --background-color_l: 20%; + --warning-color_h: 0; + --warning-color_s: 100%; + --warning-color_l: 66%; // Modifiers --brand-color--hicontrast: hsl( diff --git a/package.json b/package.json index 9682ef3094..ad53a512de 100644 --- a/package.json +++ b/package.json @@ -100,6 +100,7 @@ "postcss-object-fit-images": "^1.1.2", "prop-types": "^15.5.10", "punycode": "^2.1.0", + "qrcode.react": "^1.0.0", "rails-ujs": "^5.2.3", "react": "^16.13.1", "react-dom": "^16.13.1", diff --git a/yarn.lock b/yarn.lock index c6908bd86a..4968718442 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9320,6 +9320,20 @@ q@^1.1.2: resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= +qr.js@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/qr.js/-/qr.js-0.0.0.tgz#cace86386f59a0db8050fa90d9b6b0e88a1e364f" + integrity sha1-ys6GOG9ZoNuAUPqQ2baw6IoeNk8= + +qrcode.react@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/qrcode.react/-/qrcode.react-1.0.0.tgz#7e8889db3b769e555e8eb463d4c6de221c36d5de" + integrity sha512-jBXleohRTwvGBe1ngV+62QvEZ/9IZqQivdwzo9pJM4LQMoCM2VnvNBnKdjvGnKyDZ/l0nCDgsPod19RzlPvm/Q== + dependencies: + loose-envify "^1.4.0" + prop-types "^15.6.0" + qr.js "0.0.0" + qs@6.7.0: version "6.7.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"