Multi-Factor Auth with OTP
This commit is contained in:
parent
19e3dc9ed3
commit
68f765da28
23 changed files with 154 additions and 10 deletions
Binary file not shown.
BIN
app/soapbox/actions/mfa.js
Normal file
BIN
app/soapbox/actions/mfa.js
Normal file
Binary file not shown.
Binary file not shown.
|
@ -3,11 +3,8 @@
|
||||||
exports[`<LoginForm /> renders correctly 1`] = `
|
exports[`<LoginForm /> renders correctly 1`] = `
|
||||||
<form
|
<form
|
||||||
className="simple_form new_user"
|
className="simple_form new_user"
|
||||||
onSubmit={[Function]}
|
|
||||||
>
|
>
|
||||||
<fieldset
|
<fieldset>
|
||||||
disabled={false}
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
className="fields-group"
|
className="fields-group"
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`<LoginPage /> renders correctly 1`] = `
|
exports[`<LoginPage /> renders correctly on load 1`] = `
|
||||||
<form
|
<form
|
||||||
className="simple_form new_user"
|
className="simple_form new_user"
|
||||||
onSubmit={[Function]}
|
onSubmit={[Function]}
|
||||||
|
@ -59,4 +59,4 @@ exports[`<LoginPage /> renders correctly 1`] = `
|
||||||
</form>
|
</form>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`<LoginPage /> renders correctly 2`] = `null`;
|
exports[`<LoginPage /> renders correctly on load 2`] = `null`;
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
app/soapbox/features/auth_login/components/otp_auth_form.js
Normal file
BIN
app/soapbox/features/auth_login/components/otp_auth_form.js
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
app/soapbox/features/security/mfa_form.js
Normal file
BIN
app/soapbox/features/security/mfa_form.js
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -34,6 +34,7 @@ $small-breakpoint: 960px;
|
||||||
flex-wrap: nowrap;
|
flex-wrap: nowrap;
|
||||||
padding: 14px 0;
|
padding: 14px 0;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
@media screen and (max-width: 1024px) {
|
@media screen and (max-width: 1024px) {
|
||||||
padding: 14px 20px;
|
padding: 14px 20px;
|
||||||
|
@ -1712,7 +1713,40 @@ $small-breakpoint: 960px;
|
||||||
.header,
|
.header,
|
||||||
.container {
|
.container {
|
||||||
position: relative;
|
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;
|
bottom: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h1.otp-login {
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 24px;
|
||||||
|
font-weight: 800;
|
||||||
|
padding: 10px 0;
|
||||||
|
}
|
||||||
|
|
|
@ -72,3 +72,4 @@
|
||||||
@import 'components/video-player';
|
@import 'components/video-player';
|
||||||
@import 'components/audio-player';
|
@import 'components/audio-player';
|
||||||
@import 'components/profile_hover_card';
|
@import 'components/profile_hover_card';
|
||||||
|
@import 'components/mfa_form';
|
||||||
|
|
|
@ -102,7 +102,7 @@ button {
|
||||||
&:focus,
|
&:focus,
|
||||||
&:hover {
|
&:hover {
|
||||||
border-color: var(--brand-color);
|
border-color: var(--brand-color);
|
||||||
color: var(--primary-text-color);
|
color: var(--background-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
&:disabled {
|
&:disabled {
|
||||||
|
|
81
app/styles/components/mfa_form.scss
Normal file
81
app/styles/components/mfa_form.scss
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -255,9 +255,9 @@
|
||||||
display: block;
|
display: block;
|
||||||
margin-right: 30px;
|
margin-right: 30px;
|
||||||
border: 0;
|
border: 0;
|
||||||
height: 50px;
|
height: 40px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
padding: 10px 0;
|
padding: 13px 0 0;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
filter: brightness(0%) grayscale(100%) invert(100%);
|
filter: brightness(0%) grayscale(100%) invert(100%);
|
||||||
& span {display: none !important;}
|
& span {display: none !important;}
|
||||||
|
|
|
@ -30,12 +30,14 @@ body {
|
||||||
--accent-color: hsl(var(--accent-color_hsl));
|
--accent-color: hsl(var(--accent-color_hsl));
|
||||||
--primary-text-color: hsl(var(--primary-text-color_hsl));
|
--primary-text-color: hsl(var(--primary-text-color_hsl));
|
||||||
--background-color: hsl(var(--background-color_hsl));
|
--background-color: hsl(var(--background-color_hsl));
|
||||||
|
--warning-color: hsla(var(--warning-color_hsl));
|
||||||
|
|
||||||
// Meta-variables
|
// Meta-variables
|
||||||
--brand-color_hsl: var(--brand-color_h), var(--brand-color_s), var(--brand-color_l);
|
--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);
|
--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);
|
--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);
|
--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_h: calc(var(--brand-color_h) - 15);
|
||||||
--accent-color_s: 86%;
|
--accent-color_s: 86%;
|
||||||
--accent-color_l: 44%;
|
--accent-color_l: 44%;
|
||||||
|
@ -51,6 +53,7 @@ body {
|
||||||
calc(var(--accent-color_l) + 3%)
|
calc(var(--accent-color_l) + 3%)
|
||||||
);
|
);
|
||||||
--primary-text-color--faint: hsla(var(--primary-text-color_hsl), 0.6);
|
--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 {
|
body.theme-mode-light {
|
||||||
|
@ -69,6 +72,9 @@ body.theme-mode-light {
|
||||||
--background-color_h: 0;
|
--background-color_h: 0;
|
||||||
--background-color_s: 0%;
|
--background-color_s: 0%;
|
||||||
--background-color_l: 94.9%;
|
--background-color_l: 94.9%;
|
||||||
|
--warning-color_h: 0;
|
||||||
|
--warning-color_s: 100%;
|
||||||
|
--warning-color_l: 66%;
|
||||||
|
|
||||||
// Modifiers
|
// Modifiers
|
||||||
--brand-color--hicontrast: hsl(
|
--brand-color--hicontrast: hsl(
|
||||||
|
@ -94,6 +100,9 @@ body.theme-mode-dark {
|
||||||
--background-color_h: 0;
|
--background-color_h: 0;
|
||||||
--background-color_s: 0%;
|
--background-color_s: 0%;
|
||||||
--background-color_l: 20%;
|
--background-color_l: 20%;
|
||||||
|
--warning-color_h: 0;
|
||||||
|
--warning-color_s: 100%;
|
||||||
|
--warning-color_l: 66%;
|
||||||
|
|
||||||
// Modifiers
|
// Modifiers
|
||||||
--brand-color--hicontrast: hsl(
|
--brand-color--hicontrast: hsl(
|
||||||
|
|
|
@ -100,6 +100,7 @@
|
||||||
"postcss-object-fit-images": "^1.1.2",
|
"postcss-object-fit-images": "^1.1.2",
|
||||||
"prop-types": "^15.5.10",
|
"prop-types": "^15.5.10",
|
||||||
"punycode": "^2.1.0",
|
"punycode": "^2.1.0",
|
||||||
|
"qrcode.react": "^1.0.0",
|
||||||
"rails-ujs": "^5.2.3",
|
"rails-ujs": "^5.2.3",
|
||||||
"react": "^16.13.1",
|
"react": "^16.13.1",
|
||||||
"react-dom": "^16.13.1",
|
"react-dom": "^16.13.1",
|
||||||
|
|
14
yarn.lock
14
yarn.lock
|
@ -9320,6 +9320,20 @@ q@^1.1.2:
|
||||||
resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
|
resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
|
||||||
integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=
|
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:
|
qs@6.7.0:
|
||||||
version "6.7.0"
|
version "6.7.0"
|
||||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
|
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
|
||||||
|
|
Loading…
Reference in a new issue