web/satellite: differentiate password and passphrase autocomplete inputs

Added unique autocomplete values for password and passphrase inputs to make browser native autocomplete feature work correctly.

Issue:
https://github.com/storj/storj/issues/6151

Change-Id: I38e1bfed46beb47b3be1a620ce2a4996359feafc
This commit is contained in:
Vitalii 2023-08-09 14:08:46 +03:00 committed by Storj Robot
parent f46280c93b
commit d0c3a59f44
9 changed files with 100 additions and 13 deletions

View File

@ -8,7 +8,8 @@
<VInput
label="Encryption Passphrase"
placeholder="Enter Encryption Passphrase"
:is-password="true"
is-password
:autocomplete="autocompleteValue"
:init-value="passphrase"
@setData="setPassphrase"
/>
@ -50,6 +51,8 @@
<script setup lang="ts">
import { computed, ref } from 'vue';
import { useProjectsStore } from '@/store/modules/projectsStore';
import ButtonsContainer from '@/components/accessGrants/createFlow/components/ButtonsContainer.vue';
import Toggle from '@/components/accessGrants/createFlow/components/Toggle.vue';
import VButton from '@/components/common/VButton.vue';
@ -68,8 +71,18 @@ const props = withDefaults(defineProps<{
isNewPassphrase: false,
});
const projectsStore = useProjectsStore();
const isPassphraseSaved = ref<boolean>(false);
/**
* Returns formatted autocomplete value.
*/
const autocompleteValue = computed((): string => {
const projectID = projectsStore.state.selectedProject.id;
return `section-${projectID?.toLowerCase()} new-password`;
});
/**
* Indicates if continue button is disabled.
*/

View File

@ -30,6 +30,7 @@
:cols="40"
:maxlength="maxSymbols"
:disabled="disabled"
:autocomplete="autocomplete"
wrap="hard"
@input="onInput"
@change="onInput"
@ -45,6 +46,7 @@
:style="style.inputStyle"
:maxlength="maxSymbols"
:disabled="disabled"
:autocomplete="autocomplete"
@input="onInput"
@change="onInput"
@focus="showPasswordStrength"
@ -96,6 +98,7 @@ const props = withDefaults(defineProps<{
isWhite?: boolean,
withIcon?: boolean,
disabled?: boolean,
autocomplete?: string,
}>(), {
additionalLabel: '',
initValue: '',
@ -114,6 +117,7 @@ const props = withDefaults(defineProps<{
isWhite: false,
withIcon: false,
disabled: false,
autocomplete: 'off',
});
const emit = defineEmits(['showPasswordStrength', 'hidePasswordStrength', 'setData']);

View File

@ -14,6 +14,7 @@
label="Old Password"
placeholder="Old Password"
is-password
:autocomplete="autocompleteValue"
:error="oldPasswordError"
@setData="setOldPassword"
/>
@ -62,7 +63,7 @@
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { computed, ref } from 'vue';
import { useRouter } from 'vue-router';
import { AuthHttpApi } from '@/api/auth';
@ -80,8 +81,8 @@ import VModal from '@/components/common/VModal.vue';
import ChangePasswordIcon from '@/../static/images/account/changePasswordPopup/changePassword.svg';
const { config } = useConfigStore().state;
const analyticsStore = useAnalyticsStore();
const configStore = useConfigStore();
const appStore = useAppStore();
const notify = useNotify();
const router = useRouter();
@ -97,6 +98,13 @@ const newPasswordError = ref<string>('');
const confirmationPasswordError = ref<string>('');
const isPasswordStrengthShown = ref<boolean>(false);
/**
* Returns formatted autocomplete value.
*/
const autocompleteValue = computed((): string => {
return `section-${config.satelliteName.substring(0, 2).toLowerCase()} current-password`;
});
/**
* Enables password strength info container.
*/
@ -145,8 +153,6 @@ async function onUpdateClick(): Promise<void> {
hasError = true;
}
const config = configStore.state.config;
if (newPassword.value.length < config.passwordMinimumLength) {
newPasswordError.value = `Invalid password. Use ${config.passwordMinimumLength} or more characters`;
hasError = true;

View File

@ -20,6 +20,7 @@
:error="enterError"
role-description="passphrase"
is-password
:autocomplete="autocompleteValue"
:disabled="isLoading"
@setData="setPassphrase"
/>
@ -96,6 +97,20 @@ const passphrase = ref<string>('');
const isLoading = ref<boolean>(false);
const isWarningState = ref<boolean>(false);
/**
* Returns formatted autocomplete value.
*/
const autocompleteValue = computed((): string => {
return `section-${selectedProjectID.value.toLowerCase()} new-password`;
});
/**
* Returns selected project ID from store.
*/
const selectedProjectID = computed((): string => {
return projectsStore.state.selectedProject.id;
});
/**
* Returns chosen bucket name from store.
*/
@ -145,7 +160,7 @@ async function onContinue(): Promise<void> {
try {
bucketsStore.setPassphrase(passphrase.value);
await bucketsStore.setS3Client(projectsStore.state.selectedProject.id);
await bucketsStore.setS3Client(selectedProjectID.value);
const count: number = await bucketsStore.getObjectsCount(bucketName.value);
if (bucketObjectCount.value > count && bucketObjectCount.value <= NUMBER_OF_DISPLAYED_OBJECTS) {
isWarningState.value = true;

View File

@ -19,6 +19,7 @@
:error="enterError"
role-description="passphrase"
is-password
:autocomplete="autocompleteValue"
@setData="setPassphrase"
/>
<div class="modal__buttons">
@ -45,13 +46,14 @@
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { computed, ref } from 'vue';
import { AnalyticsErrorEventSource, AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
import { useAppStore } from '@/store/modules/appStore';
import { useBucketsStore } from '@/store/modules/bucketsStore';
import { MODALS } from '@/utils/constants/appStatePopUps';
import { useAnalyticsStore } from '@/store/modules/analyticsStore';
import { useProjectsStore } from '@/store/modules/projectsStore';
import VModal from '@/components/common/VModal.vue';
import VInput from '@/components/common/VInput.vue';
@ -62,10 +64,25 @@ import AccessEncryptionIcon from '@/../static/images/accessGrants/newCreateFlow/
const analyticsStore = useAnalyticsStore();
const bucketsStore = useBucketsStore();
const appStore = useAppStore();
const projectsStore = useProjectsStore();
const enterError = ref<string>('');
const passphrase = ref<string>('');
/**
* Returns formatted autocomplete value.
*/
const autocompleteValue = computed((): string => {
return `section-${selectedProjectID.value.toLowerCase()} new-password`;
});
/**
* Returns selected project ID from store.
*/
const selectedProjectID = computed((): string => {
return projectsStore.state.selectedProject.id;
});
/**
* Sets passphrase.
*/

View File

@ -9,10 +9,11 @@
</p>
<VInput
label="Encryption Passphrase"
:is-password="true"
is-password
width="100%"
height="56px"
placeholder="Enter Encryption Passphrase"
:autocomplete="autocompleteValue"
:error="enterError"
@setData="setPassphrase"
/>
@ -40,12 +41,13 @@
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { computed, ref } from 'vue';
import { useNotify } from '@/utils/hooks';
import { EdgeCredentials } from '@/types/accessGrants';
import { useAppStore } from '@/store/modules/appStore';
import { useBucketsStore } from '@/store/modules/bucketsStore';
import { useProjectsStore } from '@/store/modules/projectsStore';
import VButton from '@/components/common/VButton.vue';
import VInput from '@/components/common/VInput.vue';
@ -58,11 +60,26 @@ const props = withDefaults(defineProps<{
const bucketsStore = useBucketsStore();
const appStore = useAppStore();
const projectsStore = useProjectsStore();
const notify = useNotify();
const passphrase = ref<string>('');
const enterError = ref<string>('');
/**
* Returns formatted autocomplete value.
*/
const autocompleteValue = computed((): string => {
return `section-${selectedProjectID.value.toLowerCase()} new-password`;
});
/**
* Returns selected project ID from store.
*/
const selectedProjectID = computed((): string => {
return projectsStore.state.selectedProject.id;
});
/**
* Sets passphrase input value to local variable.
* Resets error is present.

View File

@ -61,6 +61,7 @@
role-description="passphrase"
placeholder="Passphrase"
:error="passphraseErr"
:autocomplete="autocompleteValue"
is-password
@setData="setPassphrase"
/>
@ -88,7 +89,7 @@
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue';
import { computed, onMounted, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { Validator } from '@/utils/validation';
@ -156,6 +157,13 @@ const oauthData = ref<{
scope?: string;
}>({});
/**
* Returns formatted autocomplete value.
*/
const autocompleteValue = computed((): string => {
return `section-${selectedProjectID.value.toLowerCase()} new-password`;
});
function slugify(name: string): string {
name = name.toLowerCase();
name = name.replace(/\s+/g, '-');

View File

@ -83,6 +83,7 @@
placeholder="Password"
:error="passwordError"
is-password
:autocomplete="autocompleteValue"
role-description="password"
@setData="setPassword"
/>
@ -222,6 +223,13 @@ const notify = useNotify();
const router = useRouter();
const route = useRoute();
/**
* Returns formatted autocomplete value.
*/
const autocompleteValue = computed((): string => {
return `section-${satelliteName.value.substring(0, 2).toLowerCase()} current-password`;
});
/**
* Name of the current satellite.
*/

View File

@ -95,8 +95,8 @@ import KeyIcon from '@/../static/images/resetPassword/success.svg';
import LogoIcon from '@/../static/images/logo.svg';
import GreyWarningIcon from '@/../static/images/common/greyWarning.svg';
const { config } = useConfigStore().state;
const analyticsStore = useAnalyticsStore();
const configStore = useConfigStore();
const appStore = useAppStore();
const notify = useNotify();
const router = useRouter();
@ -172,7 +172,6 @@ async function onResetClick(): Promise<void> {
*/
function validateFields(): boolean {
let isNoErrors = true;
const config = configStore.state.config;
if (password.value.length < config.passwordMinimumLength || password.value.length > config.passwordMaximumLength) {
passwordError.value = 'Invalid password';
@ -205,7 +204,7 @@ function hidePasswordStrength(): void {
* Redirects to storj.io homepage.
*/
function onLogoClick(): void {
window.location.href = configStore.state.config.homepageURL;
window.location.href = config.homepageURL;
}
/**