Skip to content

Commit

Permalink
Modified Password Strength Component
Browse files Browse the repository at this point in the history
  • Loading branch information
Csaern committed Jan 7, 2025
1 parent 2f3bb6c commit ad72c64
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 31 deletions.
101 changes: 73 additions & 28 deletions client/src/components/Login/PasswordStrength.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@ const props = defineProps({
const passwordStrength = ref<string>("empty");
const strengthScore = ref<number>(0);
const showPasswordGuidelines = ref(false);
const passwordRules = ref({
minLength: false,
hasNumber: false,
hasUppercase: false,
hasSpecialChar: false,
});
// Evaluate password strength using zxcvbn
function evaluatePasswordStrength(newPassword: string) {
Expand All @@ -35,18 +41,27 @@ function evaluatePasswordStrength(newPassword: string) {
}
}
// Function to validate password rules
function validatePasswordRules(password: string) {
passwordRules.value.minLength = password.length >= 12;
passwordRules.value.hasNumber = /\d/.test(password);
passwordRules.value.hasUppercase = /[A-Z]/.test(password);
passwordRules.value.hasSpecialChar = /[!@#$%^&*(),.?":{}|<>]/.test(password);
}
// Watch for changes in the password prop
watch(() => props.password, (newPassword) => {
if (typeof newPassword === "string") {
evaluatePasswordStrength(newPassword);
validatePasswordRules(newPassword || "");
}
});
</script>

<template>
<div>
<!-- Password Guidelines Button -->
<BButton variant="info" class="mt-3" @click="showPasswordGuidelines = true">
<BButton variant="info" class="mt-3" href="https://www.cisa.gov/secure-our-world/use-strong-passwords" target="_blank" rel="noopener noreferrer">
Password Guidelines
</BButton>

Expand All @@ -65,30 +80,38 @@ watch(() => props.password, (newPassword) => {
<span v-else-if="passwordStrength === 'weak'">Weak Password</span>
<span v-else-if="passwordStrength === 'medium'">Medium Password</span>
<span v-else>Strong Password</span>

</div>

<!-- Password Guidelines -->
<BModal v-model="showPasswordGuidelines" title="Tips for a secure Password">
<p>A good password should meet the following criteria:</p>
<!-- Password Guidelines with check marker-->
<div class="password-help">
<ul>
<li>At least 13 characters long.</li>
<li>Use uppercase and lowercase letters.</li>
<li>At least one number and one special character.</li>
<li>Avoid common passwords like <code>123456</code> or <code>password</code>.</li>
<li>No repeated patterns like <code>aaaa</code> or <code>123123</code>.</li>
<li :class="{ 'rule-met': passwordRules.minLength }">
<i class="fa" :class="passwordRules.minLength ? 'fa-check' : 'fa-times'"></i>
At least 12 characters
</li>
<li :class="{ 'rule-met': passwordRules.hasNumber }">
<i class="fa" :class="passwordRules.hasNumber ? 'fa-check' : 'fa-times'"></i>
Contains a number
</li>
<li :class="{ 'rule-met': passwordRules.hasUppercase }">
<i class="fa" :class="passwordRules.hasUppercase ? 'fa-check' : 'fa-times'"></i>
Contains an uppercase letter
</li>
<li :class="{ 'rule-met': passwordRules.hasSpecialChar }">
<i class="fa" :class="passwordRules.hasSpecialChar ? 'fa-check' : 'fa-times'"></i>
Contains a special character
</li>
</ul>
<template v-slot:modal-footer>
<BButton variant="secondary" @click="showPasswordGuidelines = false">Close</BButton>
</template>
</BModal>
</div>
</div>
</template>

<style scoped lang="scss">
@import "theme/blue.scss";
.password-strength-bar-container {
background-color: #f0f0f0;
background-color: $gray-200;
height: 8px;
border-radius: 4px;
overflow: hidden;
Expand All @@ -98,29 +121,51 @@ watch(() => props.password, (newPassword) => {
.password-strength-bar {
height: 100%;
transition: width 0.3s ease;
}
.password-strength-bar.weak {
background-color: $brand-danger;
}
&.weak {
background-color: $brand-danger;
}
&.medium {
background-color: $brand-warning;
}
.password-strength-bar.medium {
background-color: $brand-warning;
&.strong {
background-color: $brand-success;
}
}
.password-strength-bar.strong {
background-color: $brand-success;
.password-strength {
&.weak {
color: $brand-danger;
}
&.medium {
color: $brand-warning;
}
&.strong {
color: $brand-success;
}
}
.password-strength.weak {
color: $brand-danger;
.password-help ul {
list-style: none;
padding: 0;
}
.password-strength.medium {
color: $brand-warning;
.password-help li {
display: flex;
align-items: center;
margin: 0.2rem;
}
.password-strength.strong {
.password-help li.rule-met {
color: $brand-success;
}
.password-help li .fa {
margin-right: 0.5rem;
}
</style>
36 changes: 33 additions & 3 deletions client/src/components/Login/RegisterForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ interface Props {
}
const props = defineProps<Props>();
const showPassword = ref(false);
const emit = defineEmits<{
(e: "toggle-login"): void;
Expand All @@ -64,6 +65,10 @@ function toggleLogin() {
emit("toggle-login");
}
function togglePasswordVisibility() {
showPassword.value = !showPassword.value;
}
async function submit() {
disableCreate.value = true;
Expand Down Expand Up @@ -145,10 +150,20 @@ async function submit() {
id="register-form-password"
v-model="password"
name="password"
type="password"
:type="showPassword ? 'text' : 'password'"
autocomplete="new-password"
required
required
/>
<!-- Eye Icon to show Password -->
<button
type="button"
class="password-toggle-icon"
@click="togglePasswordVisibility"
aria-label="Toggle password visibility"
>
<i :class="showPassword ? 'fa fa-eye-slash' : 'fa fa-eye'"></i>
</button>

<!-- Password Strength Component -->
<PasswordStrength :password="password" />
</BFormGroup>
Expand Down Expand Up @@ -245,6 +260,21 @@ async function submit() {
border: 1px solid #ccc;
padding: 2px 5px;
border-radius: 4px;
}
}
}
.password-toggle-icon {
position: absolute;
right: 0.75rem;
background: none;
border: none;
cursor: pointer;
color: $gray-600;
font-size: 1rem;
}
.password-toggle-icon:hover {
color: $gray-900;
}
</style>

0 comments on commit ad72c64

Please sign in to comment.