vps

ساخت یک مقیاس اندازه گیری قدرت رمز عبور را در React

رمزهای عبور معمولاً برای تأیید اعتبار کاربر در بیشتر برنامه های وب استفاده می شوند. به همین دلیل لازم است که گذرواژه‌ها به روشی ایمن ذخیره شوند. در طول سالها ، از تکنیک هایی مانند هش کردن (در هم سازی) رمز عبور یک طرفه استفاده شده است تا نمایش واقعی رمزهای ذخیره شده در یک پایگاه داده را مخفی کند. اما اگرچه درهم سازی گذرواژه قدم بزرگی در جهت ایمن سازی رمز عبور است ، کاربر هنوز هم یک مشکل بزرگ برای امنیت رمز عبور دارد. کاربرانی که از کلمه رایجی به عنوان رمز عبور استفاده می کنند ، عمل hashing را بی فایده می کنند، زیرا یک حمله brute-force می تواند به سرعت چنین رمزهایی را خراب کند.
برای پرداختن به این موضوع ، بسیاری از برنامه های وب امروز اصرار دارند که کاربران از گذرواژه های قوی برخوردار باشند ، و یا با حداقل طول رمز عبور و یا ترکیبی از کاراکترها و نمادهای الفبا در رمز عبور این کار را انجام میدهند. برای اندازه‌گیری قدرت رمز عبور ، Dropbox الگوریتمی برای تخمین قدرت واقعی رمز عبور با الهام از crackerهای رمز عبور ایجاد کرده است. این الگوریتم در یک کتابخانه جاوا اسکریپت به نام zxcvbn بسته بندی شده است. علاوه بر این ، این بسته شامل فرهنگ لغت کلمات متداول انگلیسی ، نام ها و کلمات عبور است.
در این آموزش با استفاده از چارچوب جاوااسکریپت React یک فرم با فیلدهایی برای نام کامل ، ایمیل و رمز عبور ایجاد خواهیم کرد. اندکی اعتبارسنجی سبک برای فرم انجام خواهیم داد و همچنین از کتابخانه zxcvbn برای برآورد قدرت پسورد در فرم استفاده می کنیم و ضمنا بازخورد بصری را ارائه میکنیم.
این نسخه نمایشی CodeSandbox از آنچه تا پایان این آموزش ایجاد خواهیم کرد را بررسی کنید.
پیش نیازها
قبل از شروع کار ، اطمینان حاصل کنید که نسخه جدیدی از Node را روی سیستم خود نصب کرده باشید. ما از yarn برای اجرای تمام اسکریپت های NPM و نصب متعلقات برای پروژه خود استفاده خواهیم کرد ، بنابراین همچنین از نصب yarn اطمینان حاصل کنید. برای نصب yarn روی سیستم می توانید از این راهنمای نصب yarn استفاده کنید. همچنین ، برای تولید برنامه جدید React خود ، از بسته محبوب create-react-app استفاده خواهیم کرد.
اگر قبلاً آن را نصب نکرده اید ، دستور زیر را اجرا کنید تا برنامه create-react-app را در سیستم خود نصب کنید.
npm install -g create-react-app

مرحله 1 – تنظیم برنامه خود
یک برنامه جدید React را با استفاده از دستور زیر شروع کنید. می توانید برنامه را هر طور که می خواهید نامگذاری کنید.
توجه: اگر از npm نسخه 5.2 یا بالاتر استفاده می کنید ، با یک باینری npx اضافی همراه است. با استفاده از باینری npx ، دیگر نیازی نیست که برنامه create-react-app را در سطح جهانی روی سیستم خود نصب کنید. با استفاده از این دستور می توانید برنامه جدید React را شروع کنید: npx create-react-app react-password-strength

در مرحله بعد ، متعلقات مورد نیاز برنامه خود را نصب خواهیم کرد. برای نصب متعلقات لازم ، دستور زیر را اجرا کنید.
$ yarn add bootstrap zxcvbn isemail prop-types

$ yarn add -D npm-run-all node-sass-chokidar

ما node-sass-chokida را به عنوان یک وابستگی توسعه برای برنامه خود نصب کرده ایم تا ما را قادر به استفاده از SASS کند. برای اطلاعات بیشتر در مورد این ، به این راهنما مراجعه کنید.
اکنون دیرکتوری src را باز کرده و پسوند فایل همه فایل های .css را به .scss تغییر دهید. فایل های .css مورد نیاز در ادامه کار توسط node-sass-chokidar کامپایل می شوند.
فایل pack.json را ویرایش کرده و بخش scripts  را تغییر دهید تا به شکل زیر باشد:
“scripts”: {
“start:js”: “react-scripts start”,
“build:js”: “react-scripts build”,
“start”: “npm-run-all -p watch:css start:js”,
“build”: “npm-run-all build:css build:js”,
“test”: “react-scripts test –env=jsdom”,
“eject”: “react-scripts eject”,
“build:css”: “node-sass-chokidar –include-path ./src –include-path ./node_modules src/ -o src/”,
“watch:css”: “npm run build:css && node-sass-chokidar –include-path ./src –include-path ./node_modules src/ -o src/ –watch –recursive”
}

همانطور که ممکن است متوجه شده باشید ، ما بسته bootstrap  را به عنوان یک وابستگی برای برنامه خود نصب کرده ایم تا یک ظاهر طراحی پیش فرض را بدست آوریم. برای وارد کردن Bootstrap در برنامه ، فایل src / index.js را ویرایش کنید و قبل از هر عبارت import  دیگر خط زیر را اضافه کنید.
import “bootstrap/dist/css/bootstrap.min.css”;

در آخر ، درخواست خود را شروع کنید:
$ yarn start

برنامه اکنون شروع شده است و توسعه می تواند آغاز شود. توجه کنید که یک سربرگ مرورگر با عملکرد لود مجدد زنده برای شما باز شده است تا همزمان با ایجاد برنامه ، با تغییرات در برنامه همگام شوید.
در این مرحله ، نمای برنامه شما مانند تصویر زیر خواهد بود:

مرحله 2 – ساختن مولفه ها
به یاد داشته باشید که قصد داریم یک فرم با فیلدهای مربوط به نام کامل ، ایمیل و رمز عبور ایجاد کنیم و همچنین برخی از اعتبار سنجی های سبک را در این فیلدها انجام دهیم. مولفه های React زیر را ایجاد می کنیم:
FormField – یک فیلد ورودی فرم را با ویژگی های آن پوشش میدهد و کنترل کننده رویداد را تغییر میدهد.
EmailField – ایمیل FormField را دربرگرفته و منطق اعتبار سنجی ایمیل را به آن اضافه می کند.
PasswordField – رمز عبور FormField را محصور کرده و منطق اعتبار رمز عبور را به آن اضافه می کند. همچنین مقیاس قدرت رمز عبور و برخی از نشانه های بصری دیگر را به فیلد وصل می کند.
JoinForm – تیم حمایت عضویت که فیلدهای فرم را در خود جای میدهد.
پیش بروید و یک دیرکتوری components  در داخل فهرست src برنامه ایجاد کنید تا تمام اجزای ما در آن قرار بگیرند.
مؤلفه FormField
یک فایل جدید FormField.js را در دیرکتوری src / parts ایجاد کنید و قطعه کد زیر را به آن اضافه کنید:
import React, { Component, Fragment } from ‘react’;
import PropTypes from ‘prop-types’;

class FormField extends Component {

// initialize state
state = { value: ”, dirty: false, errors: [] }

hasChanged = e => {
e.preventDefault();

// destructure props – assign default dummy functions to validator and onStateChanged props
const { label, required = false, validator = f => f, onStateChanged = f => f } = this.props;

const value = e.target.value;
const isEmpty = value.length === 0;
const requiredMissing = this.state.dirty && required && isEmpty;

let errors = [];

if (requiredMissing) {
// if required and is empty, add required error to state
errors = [ …errors, `${label} is required` ];
} else if (‘function’ === typeof validator) {
try {
validator(value);
} catch (e) {
// if validator throws error, add validation error to state
errors = [ …errors, e.message ];
}
}

// update state and call the onStateChanged callback fn after the update
// dirty is only changed to true and remains true on and after the first state update
this.setState(({ dirty = false }) => ({ value, errors, dirty: !dirty || dirty }), () => onStateChanged(this.state));
}

render() {
const { value, dirty, errors } = this.state;
const { type, label, fieldId, placeholder, children } = this.props;

const hasErrors = errors.length > 0;
const controlClass = [‘form-control’, dirty ? hasErrors ? ‘is-invalid’ : ‘is-valid’ : ” ].join(‘ ‘).trim();

return (
<Fragment>
<div className=”form-group px-3 pb-2″>
<div className=”d-flex flex-row justify-content-between align-items-center”>
<label htmlFor={fieldId} className=”control-label”>{label}</label>
{/** Render the first error if there are any errors **/}
{ hasErrors && <div className=”error form-hint font-weight-bold text-right m-0 mb-2″>{ errors[0] }</div> }
</div>
{/_ Render the children nodes passed to component _/}
{children}
<input type={type} className={controlClass} id={fieldId} placeholder={placeholder} value={value} onChange={this.hasChanged} />
</div>
</Fragment>
);
}

}

FormField.propTypes = {
type: PropTypes.oneOf([“text”, “password”]).isRequired,
label: PropTypes.string.isRequired,
fieldId: PropTypes.string.isRequired,
placeholder: PropTypes.string.isRequired,
required: PropTypes.bool,
children: PropTypes.node,
validator: PropTypes.func,
onStateChanged: PropTypes.func
};

export default FormField;

در این بخش اندک مواردی روی این مولفه انجام می دهیم. بیایید سعی کنیم کمی آن را تجزیه کنیم:
Input State: ابتدا حالت را برای مؤلفه فیلد فرم تنظیم می کنیم تا مقدار فعلی فیلد ورودی ، وضعیت dirty  این فیلد و هرگونه خطای اعتبار سنجی موجود را ردیابی کنیم. هنگامی که مقدار یک فیلد برای اولین بار تغییر کند و dirty (کثیف) باقی بماند ، تبدیل به یک فیلد dirty می شود.
Handle Input Change: سپس کنترلر رویداد hasChanged (e) را اضافه کردیم تا مقدار حالت را به مقدار ورودی فعلی در هر تغییر در ورودی به روز کند. در هندلر وضعیت کثیف فیلد را نیز برطرف می کنیم. بررسی می کنیم که آیا این فیلد یک فیلد مورد نیاز بر اساس مشخصه ها است یا خیر ، و اگر مقدار خالی باشد ، یک خطای اعتبارسنجی به آرایه خطاهای حالت اضافه می کنیم.
اما ، اگر این فیلد یک فیلد لازم نیست یا لازم است اما خالی نیست ، به سراغ عملکرد اعتبارسنجی منتقل شده در مشخصه اعتبارسنجی اختیاری میرویم، آن را با مقدار ورودی فعلی فراخوانی می کنیم و خطای اعتبار سنجی حاصل را به آرایه خطاهای حالت اضافه می کنیم. (در صورت بروز هرگونه خطا).
در آخر ، وضعیت را به روز می کنیم و یک تابع callbackفراخوانی میکنیم که پس از بروزرسانی فراخوانی می شود. تابع callback ، تابع منتقل شده در مشخصه اختیاری onStateChanged را فراخوانی می کند ، و حالت جدید را به عنوان آرگومان خود وارد می کند. این امر برای انتشار تغییرات حالت در خارج از مؤلفه مفید خواهد بود.
Rendering and Props در اینجا فیلد ورودی و برچسب آن را ارائه می دهیم. همچنین به طور مشروط اولین خطای موجود در آرایه خطاهای حالت (در صورت بروز هر گونه خطا) را ارائه می دهیم. توجه کنید که چگونه کلاس ها را برای قسمت ورودی به صورت پویا تنظیم کرده ایم تا با استفاده از کلاس های داخلی Bootstrap ، وضعیت اعتبار سنجی را نشان دهند. همچنین گره های کودک موجود در این مولفه را ارائه می دهیم.
همانطور که در propType های مؤلفه مشاهده می شود ، مشخصه های لازم برای این مؤلفه عبارتند از: type (“text” یا “password “) ، label ، placeholder و field. مولفه های باقیمانده اختیاری هستند.
مؤلفه EmailField
یک فایل جدید EmailField.js را در دیرکتوری src / parts ایجاد کنید و قطعه کد زیر را به آن اضافه کنید.
import React from ‘react’;
import PropTypes from ‘prop-types’;
import { validate } from ‘isemail’;

import FormField from ‘./FormField’;

const EmailField = props => {

// prevent passing type and validator props from this component to the rendered form field component
const { type, validator, …restProps } = props;

// validateEmail function using the validate() method of the isemail package
const validateEmail = value => {
if (!validate(value)) throw new Error(‘Email is invalid’);
};

// pass the validateEmail to the validator prop
return <FormField type=”text” validator={validateEmail} {…restProps} />
};

EmailField.propTypes = {
label: PropTypes.string.isRequired,
fieldId: PropTypes.string.isRequired,
placeholder: PropTypes.string.isRequired,
required: PropTypes.bool,
children: PropTypes.node,
onStateChanged: PropTypes.func
};

export default EmailField;

در مؤلفه EmailField ، به سادگی یک مؤلفه FormField را ارائه می دهیم و یک عملکرد اعتبارسنجی ایمیل را به مشخصه اعتبارسنجی منتقل می کنیم. برای اعتبار سنجی ایمیل از روش validate() بسته isemail  استفاده می کنیم.
همچنین توجه داشته باشید که تمام مشخصه های دیگر به غیر از type  و validator  از مؤلفه EmailField به مؤلفه FormField منتقل می شوند.
مؤلفه PasswordField
یک فایل جدید PasswordField.js را در دیرکتوری src / parts ایجاد کنید و قطعه کد زیر را به آن اضافه کنید:
import React, { Component, Fragment } from ‘react’;
import PropTypes from ‘prop-types’;
import zxcvbn from ‘zxcvbn’;

import FormField from ‘./FormField’;

class PasswordField extends Component {

constructor(props) {

super(props);
const { minStrength = 3, thresholdLength = 7 } = props;

// set default minStrength to 3 if not a number or not specified
// minStrength must be a a number between 0 – 4

this.minStrength = typeof minStrength === ‘number’
? Math.max( Math.min(minStrength, 4), 0 )
: 3;

// set default thresholdLength to 7 if not a number or not specified
// thresholdLength must be a minimum value of 7

this.thresholdLength = typeof thresholdLength === ‘number’
? Math.max(thresholdLength, 7)
: 7;

// initialize internal component state
this.state = { password: ”, strength: 0 };
}

stateChanged = state => {

// update the internal state using the updated state from the form field

this.setState({
password: state.value,
strength: zxcvbn(state.value).score
}, () => this.props.onStateChanged(state));

};

validatePasswordStrong = value => {
// ensure password is long enough
if (value.length <= this.thresholdLength) throw new Error(“Password is short”);

// ensure password is strong enough using the zxcvbn library
if (zxcvbn(value).score < this.minStrength) throw new Error(“Password is weak”);
};

render() {
const { type, validator, onStateChanged, children, …restProps } = this.props;
const { password, strength } = this.state;

const passwordLength = password.length;
const passwordStrong = strength >= this.minStrength;
const passwordLong = passwordLength > this.thresholdLength;

// dynamically set the password length counter class
const counterClass = [‘badge badge-pill’, passwordLong ? passwordStrong ? ‘badge-success’ : ‘badge-warning’ : ‘badge-danger’].join(‘ ‘).trim();

// password strength meter is only visible when password is not empty
const strengthClass = [‘strength-meter mt-2’, passwordLength > 0 ? ‘visible’ : ‘invisible’].join(‘ ‘).trim();

return (
<Fragment>
<div className=”position-relative”>
{/** Pass the validation and stateChanged functions as props to the form field **/}
<FormField type=”password” validator={this.validatePasswordStrong} onStateChanged={this.stateChanged} {…restProps}>
<span className=”d-block form-hint”>To conform with our Strong Password policy, you are required to use a sufficiently strong password. Password must be more than 7 characters.</span>
{children}
{/** Render the password strength meter **/}
<div className={strengthClass}>
<div className=”strength-meter-fill” data-strength={strength}></div>
</div>
</FormField>
<div className=”position-absolute password-count mx-3″>
{/** Render the password length counter indicator **/}
<span className={counterClass}>{ passwordLength ? passwordLong ? `${this.thresholdLength}+` : passwordLength : ” }</span>
</div>
</div>
</Fragment>
);
}

}

PasswordField.propTypes = {
label: PropTypes.string.isRequired,
fieldId: PropTypes.string.isRequired,
placeholder: PropTypes.string.isRequired,
required: PropTypes.bool,
children: PropTypes.node,
onStateChanged: PropTypes.func,
minStrength: PropTypes.number,
thresholdLength: PropTypes.number
};

export default PasswordField;

ما در این مؤلفه از بسته تخمین قدرت رمز عبور zxcvbn در جاوااسکریپت استفاده می کنیم. این بسته یک تابعzxcvbn () را صادر می کند که یک (کلمه عبور: رشته) را به عنوان اولین آرگومان خود در نظر می گیرد و یک شیء را با چندین ویژگی برای برآورد قدرت پسورد باز می گرداند. در این آموزش ، ما فقط به ویژگی امتیاز میپردازیم ، که عدد صحیحی بین 0 – 4 است (برای اجرای نوار قدرت مفید است).
در اینجا به تفصیل آنچه در مؤلفه PasswordField در جریان است ، می پردازیم.
Initialization  – در constructor() ، ما دو ویژگی نمونه ایجاد کردیم: thresholdLangth  و minStrength  از قسمت مربوطه که به مؤلفه منتقل شده اند. thresholdLength (طول آستانه) حداکثر طول رمز عبور است قبل از آنکه به طرز قابل توجهی طولانی در نظر گرفته شود. پیش فرض 7 است و نمی تواند پایین تر باشد. minStrength حداقل نمره zxcvbn است قبل از اینکه رمز عبور به اندازه کافی قوی در نظر گرفته می شود. مقدار آن از 0-4 متغیر است. اگر به درستی مشخص نشده باشد ، پیش فرض 3 قرار میگیرد.
همچنین برای ذخیره رمز عبور فعلی و قدرت رمز عبور ، حالت داخلی فیلد رمز عبور را مقداردهی اولیه کردیم.
Handling Password Changes – یک تابع اعتبار سنجی گذرواژه تعریف کردیم که به مشخصه اعتبارسنجی مؤلفه FormField منتقل می شود. این تابع تضمین می کند که طول رمز عبور طولانی تر از طول آستانه است و همچنین دارای یک نمره حداقل zxcvbn () از minStrength مشخص شده است.
همچنین یک تابع stateChanged () تعریف کردیم ، که به مشخصه onStateChanged از مؤلفه FormField منتقل خواهد شد. این عملکرد حالت به روز شده از مؤلفه FormField را بازیابی می کند و از آن برای محاسبه و به روزرسانی وضعیت داخلی جدید مؤلفه PasswordField استفاده می کند.
یک تابع callback باید بعد از بروزرسانی حالت داخلی فراخوانی شود. تابع callback ، تابع منتقل شده در قسمت اختیاری onStateChanged از مؤلفه PasswordField را فراخوانی می کند و حالت به روز شده FormField را به عنوان آرگومان خود وارد میکند.
Rendering and Props – در اینجا به راحتی عنصر زیربنایی FormField را در کنار بعضی از عناصر برای اشاره ورودی ، سنجش قدرت رمز عبور ، و شمارنده طول رمزعبور ارائه کردیم.
مقیاس رمز عبور، قدرت رمز عبور فعلی را بر اساس حالت نشان می دهد و به گونه ای پیکربندی شده است که اگر طول رمز عبور 0 باشد به صورت پویا قابل مشاهده نباشد. این مقیاس برای سطوح مختلف قدرت رنگ های مختلف را نشان می دهد.
شمارنده طول رمز عبور ، نشان می دهد چه زمان طول پسورد کافی است. اگر رمز عبور از طول آستانه طولانی تر نباشد ، طول رمز عبور را نشان می دهد ، در غیر این صورت طول آستانه را به همراه یک (+) نشان می دهد.
مؤلفه PasswordField دو قسمت اختیاری دیگر را می پذیرد: minStrength و thresholdLength به همان صورت که در propTypes های مؤلفه تعریف شده است.
مولفه JoinForm
یک فایل جدید JoinForm.js را در دیرکتوری src / parts ایجاد کنید و قطعه کد زیر را به آن اضافه کنید:
import React, { Component } from ‘react’;

import FormField from ‘./FormField’;
import EmailField from ‘./EmailField’;
import PasswordField from ‘./PasswordField’;

class JoinForm extends Component {

// initialize state to hold validity of form fields
state = { fullname: false, email: false, password: false }

// higher-order function that returns a state change watch function
// sets the corresponding state property to true if the form field has no errors
fieldStateChanged = field => state => this.setState({ [field]: state.errors.length === 0 });

// state change watch functions for each field
emailChanged = this.fieldStateChanged(’email’);
fullnameChanged = this.fieldStateChanged(‘fullname’);
passwordChanged = this.fieldStateChanged(‘password’);

render() {
const { fullname, email, password } = this.state;
const formValidated = fullname && email && password;

// validation function for the fullname
// ensures that fullname contains at least two names separated with a space
const validateFullname = value => {
const regex = /^[a-z]{2,}(\s[a-z]{2,})+$/i;
if (!regex.test(value)) throw new Error(‘Fullname is invalid’);
};

return (
<div className=”form-container d-table-cell position-relative align-middle”>
<form action=”/” method=”POST” noValidate>

<div className=”d-flex flex-row justify-content-between align-items-center px-3 mb-5″>
<legend className=”form-label mb-0″>Support Team</legend>
{/** Show the form button only if all fields are valid **/}
{ formValidated && <button type=”button” className=”btn btn-primary text-uppercase px-3 py-2″>Join</button> }
</div>

<div className=”py-5 border-gray border-top border-bottom”>
{/** Render the fullname form field passing the name validation fn **/}
<FormField type=”text” fieldId=”fullname” label=”Fullname” placeholder=”Enter Fullname” validator={validateFullname} onStateChanged={this.fullnameChanged} required />

{/** Render the email field component **/}
<EmailField fieldId=”email” label=”Email” placeholder=”Enter Email Address” onStateChanged={this.emailChanged} required />

{/** Render the password field component using thresholdLength of 7 and minStrength of 3 **/}
<PasswordField fieldId=”password” label=”Password” placeholder=”Enter Password” onStateChanged={this.passwordChanged} thresholdLength={7} minStrength={3} required />
</div>

</form>
</div>
);
}

}

export default JoinForm;

مولفه JoinForm اجزای فیلد فرم را دربرمیگیرد که فرم ما را تشکیل می دهد. ما برای حفظ اعتبار سه فیلد فرم ، حالت اولیه را تنظیم کردیم: نام کامل ، ایمیل و رمز عبور. همه آنها در ابتدا false  هستند – که نامعتبر است.
همچنین توابع مشاهده تغییر حالت را برای هر فیلد تعریف کردیم تا حالت فرم را بر این اساس آپدیت کند. تابع watch  بررسی میکند که در یک فیلد خطایی نباشد و حالت داخلی فرم را برای آن فیلد روی true به روز می کند – که معتبر است. سپس این توابع مشاهده به نظارت بر onStateChanged هر مؤلفه فیلد فرم اختصاص داده می شوند تا تغییرات وضعیت را کنترل کنند.
سرانجام فرم را ارائه دادیم. توجه کنید که ما یک تابع اعتبارسنجی را به فیلد fullname  اضافه کرده ایم تا اطمینان حاصل شود که دو نام حداقل با فاصله (space) جدا شده اند و فقط حاوی کاراکترهای الفبا هستند.
مؤلفه App
تا این مرحله ، مرورگر هنوز برنامه React  را ارائه می دهد. پیش خواهیم رفت تا فایل App.js را در دیرکتوری src اصلاح کنیم تا JoinForm را در داخل AppComponent ارائه دهیم.
فایل App.js باید مانند قطعه زیر باشد:
import React from ‘react’;
import JoinForm from ‘./components/JoinForm’;
import ‘./App.css’;

const App = () => (
<div className=”main-container d-table position-absolute m-auto”>
<JoinForm />
</div>
);

export default App;

مرحله 3 – طراحی با SASS
یک قدم از ظاهر نهایی برنامه خود فاصله داریم. در حال حاضر ، به نظر می رسد همه چیز کمی خارج از مکان خود قرار دارد. پیش خواهیم رفت تا برخی از قوانین استایل را در فایل src / App.scss تعریف کنیم تا فرم مورد نظر را طراحی کنیم.
فایل App.scss مانند قطعه کد زیر خواهد شد:
/_ Declare some variables _/
$primary: #007bff;

// Password strength meter color for the different levels
$strength-colors: (darkred, orangered, orange, yellowgreen, green);

// Gap width between strength meter bars
$strength-gap: 6px;

body {
font-size: 62.5%;
}

.main-container {
width: 400px;
top: 0;
bottom: 0;
left: 0;
right: 0;
}

.form-container {
bottom: 100px;
}

legend.form-label {
font-size: 1.5rem;
color: desaturate(darken($primary, 10%), 60%);
}

.control-label {
font-size: 0.8rem;
font-weight: bold;
color: desaturate(darken($primary, 10%), 80%);
}

.form-control {
font-size: 1rem;
}

.form-hint {
font-size: 0.6rem;
line-height: 1.4;
margin: -5px auto 5px;
color: #999;

&.error {
color: #C00;
font-size: 0.8rem;
}
}

button.btn {
letter-spacing: 1px;
font-size: 0.8rem;
font-weight: 600;
}

.password-count {
bottom: 16px;
right: 10px;
font-size: 1rem;
}

.strength-meter {
position: relative;
height: 3px;
background: #DDD;
margin: 7px 0;
border-radius: 2px;

// Dynamically create the gap effect
&:before,
&:after {
content: ”;
height: inherit;
background: transparent;
display: block;
border-color: #FFF;
border-style: solid;
border-width: 0 $strength-gap 0;
position: absolute;
width: calc(20% + #{$strength-gap});
z-index: 10;
}

// Dynamically create the gap effect
&:before {
left: calc(20% – #{($strength-gap / 2)});
}

// Dynamically create the gap effect
&:after {
right: calc(20% – #{($strength-gap / 2)});
}
}

.strength-meter-fill {
background: transparent;
height: inherit;
position: absolute;
width: 0;
border-radius: inherit;
transition: width 0.5s ease-in-out, background 0.25s;

// Dynamically generate strength meter color styles
@for $i from 1 through 5 {
&[data-strength=’#{$i – 1}’] {
width: (20% * $i);
background: nth($strength-colors, $i);
}
}
}

ما موفق شده ایم که سبک های مورد نیاز برنامه خود را اضافه کنیم. به استفاده از محتوای CSS تولید شده در شبه عناصر .strength-meter:before و .strength-meter:after توجه کنید تا گپ هایی به مقیاس قدرت پسورد اضافه