satellite/{web, console}: removed old project level passphrase flow

Removed old behavior and bucket creation flow.

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

Change-Id: I1a443911215cd1f611069fd9e6202598066b80b2
This commit is contained in:
Vitalii 2023-01-31 22:42:16 +02:00 committed by Storj Robot
parent 382af95499
commit 5377b9c314
23 changed files with 109 additions and 1528 deletions

View File

@ -68,35 +68,34 @@ type Config struct {
AuthToken string `help:"auth token needed for access to registration token creation endpoint" default:"" testDefault:"very-secret-token"`
AuthTokenSecret string `help:"secret used to sign auth tokens" releaseDefault:"" devDefault:"my-suppa-secret-key"`
ContactInfoURL string `help:"url link to contacts page" default:"https://forum.storj.io"`
FrameAncestors string `help:"allow domains to embed the satellite in a frame, space separated" default:"tardigrade.io storj.io"`
LetUsKnowURL string `help:"url link to let us know page" default:"https://storjlabs.atlassian.net/servicedesk/customer/portals"`
SEO string `help:"used to communicate with web crawlers and other web robots" default:"User-agent: *\nDisallow: \nDisallow: /cgi-bin/"`
SatelliteName string `help:"used to display at web satellite console" default:"Storj"`
SatelliteOperator string `help:"name of organization which set up satellite" default:"Storj Labs" `
TermsAndConditionsURL string `help:"url link to terms and conditions page" default:"https://www.storj.io/terms-of-service/"`
AccountActivationRedirectURL string `help:"url link for account activation redirect" default:""`
PartneredSatellites console.Satellites `help:"names and addresses of partnered satellites in JSON list format" default:"[{\"name\":\"US1\",\"address\":\"https://us1.storj.io\"},{\"name\":\"EU1\",\"address\":\"https://eu1.storj.io\"},{\"name\":\"AP1\",\"address\":\"https://ap1.storj.io\"}]"`
GeneralRequestURL string `help:"url link to general request page" default:"https://supportdcs.storj.io/hc/en-us/requests/new?ticket_form_id=360000379291"`
ProjectLimitsIncreaseRequestURL string `help:"url link to project limit increase request page" default:"https://supportdcs.storj.io/hc/en-us/requests/new?ticket_form_id=360000683212"`
GatewayCredentialsRequestURL string `help:"url link for gateway credentials requests" default:"https://auth.storjshare.io" devDefault:"http://localhost:8000"`
IsBetaSatellite bool `help:"indicates if satellite is in beta" default:"false"`
BetaSatelliteFeedbackURL string `help:"url link for for beta satellite feedback" default:""`
BetaSatelliteSupportURL string `help:"url link for for beta satellite support" default:""`
DocumentationURL string `help:"url link to documentation" default:"https://docs.storj.io/"`
CouponCodeBillingUIEnabled bool `help:"indicates if user is allowed to add coupon codes to account from billing" default:"false"`
CouponCodeSignupUIEnabled bool `help:"indicates if user is allowed to add coupon codes to account from signup" default:"false"`
FileBrowserFlowDisabled bool `help:"indicates if file browser flow is disabled" default:"false"`
CSPEnabled bool `help:"indicates if Content Security Policy is enabled" devDefault:"false" releaseDefault:"true"`
LinksharingURL string `help:"url link for linksharing requests" default:"https://link.storjshare.io" devDefault:"http://localhost:8001"`
PathwayOverviewEnabled bool `help:"indicates if the overview onboarding step should render with pathways" default:"true"`
NewProjectDashboard bool `help:"indicates if new project dashboard should be used" default:"true"`
NewBillingScreen bool `help:"indicates if new billing screens should be used" default:"true"`
GeneratedAPIEnabled bool `help:"indicates if generated console api should be used" default:"false"`
OptionalSignupSuccessURL string `help:"optional url to external registration success page" default:""`
HomepageURL string `help:"url link to storj.io homepage" default:"https://www.storj.io"`
NativeTokenPaymentsEnabled bool `help:"indicates if storj native token payments system is enabled" default:"false"`
NewEncryptionPassphraseFlowEnabled bool `help:"indicates if new encryption passphrase flow is enabled" default:"true"`
ContactInfoURL string `help:"url link to contacts page" default:"https://forum.storj.io"`
FrameAncestors string `help:"allow domains to embed the satellite in a frame, space separated" default:"tardigrade.io storj.io"`
LetUsKnowURL string `help:"url link to let us know page" default:"https://storjlabs.atlassian.net/servicedesk/customer/portals"`
SEO string `help:"used to communicate with web crawlers and other web robots" default:"User-agent: *\nDisallow: \nDisallow: /cgi-bin/"`
SatelliteName string `help:"used to display at web satellite console" default:"Storj"`
SatelliteOperator string `help:"name of organization which set up satellite" default:"Storj Labs" `
TermsAndConditionsURL string `help:"url link to terms and conditions page" default:"https://www.storj.io/terms-of-service/"`
AccountActivationRedirectURL string `help:"url link for account activation redirect" default:""`
PartneredSatellites console.Satellites `help:"names and addresses of partnered satellites in JSON list format" default:"[{\"name\":\"US1\",\"address\":\"https://us1.storj.io\"},{\"name\":\"EU1\",\"address\":\"https://eu1.storj.io\"},{\"name\":\"AP1\",\"address\":\"https://ap1.storj.io\"}]"`
GeneralRequestURL string `help:"url link to general request page" default:"https://supportdcs.storj.io/hc/en-us/requests/new?ticket_form_id=360000379291"`
ProjectLimitsIncreaseRequestURL string `help:"url link to project limit increase request page" default:"https://supportdcs.storj.io/hc/en-us/requests/new?ticket_form_id=360000683212"`
GatewayCredentialsRequestURL string `help:"url link for gateway credentials requests" default:"https://auth.storjshare.io" devDefault:"http://localhost:8000"`
IsBetaSatellite bool `help:"indicates if satellite is in beta" default:"false"`
BetaSatelliteFeedbackURL string `help:"url link for for beta satellite feedback" default:""`
BetaSatelliteSupportURL string `help:"url link for for beta satellite support" default:""`
DocumentationURL string `help:"url link to documentation" default:"https://docs.storj.io/"`
CouponCodeBillingUIEnabled bool `help:"indicates if user is allowed to add coupon codes to account from billing" default:"false"`
CouponCodeSignupUIEnabled bool `help:"indicates if user is allowed to add coupon codes to account from signup" default:"false"`
FileBrowserFlowDisabled bool `help:"indicates if file browser flow is disabled" default:"false"`
CSPEnabled bool `help:"indicates if Content Security Policy is enabled" devDefault:"false" releaseDefault:"true"`
LinksharingURL string `help:"url link for linksharing requests" default:"https://link.storjshare.io" devDefault:"http://localhost:8001"`
PathwayOverviewEnabled bool `help:"indicates if the overview onboarding step should render with pathways" default:"true"`
NewProjectDashboard bool `help:"indicates if new project dashboard should be used" default:"true"`
NewBillingScreen bool `help:"indicates if new billing screens should be used" default:"true"`
GeneratedAPIEnabled bool `help:"indicates if generated console api should be used" default:"false"`
OptionalSignupSuccessURL string `help:"optional url to external registration success page" default:""`
HomepageURL string `help:"url link to storj.io homepage" default:"https://www.storj.io"`
NativeTokenPaymentsEnabled bool `help:"indicates if storj native token payments system is enabled" default:"false"`
OauthCodeExpiry time.Duration `help:"how long oauth authorization codes are issued for" default:"10m"`
OauthAccessTokenExpiry time.Duration `help:"how long oauth access tokens are issued for" default:"24h"`
@ -428,46 +427,45 @@ func (server *Server) appHandler(w http.ResponseWriter, r *http.Request) {
header.Set("Referrer-Policy", "same-origin") // Only expose the referring url when navigating around the satellite itself.
var data struct {
ExternalAddress string
SatelliteName string
SatelliteNodeURL string
StripePublicKey string
PartneredSatellites string
DefaultProjectLimit int
GeneralRequestURL string
ProjectLimitsIncreaseRequestURL string
GatewayCredentialsRequestURL string
IsBetaSatellite bool
BetaSatelliteFeedbackURL string
BetaSatelliteSupportURL string
DocumentationURL string
CouponCodeBillingUIEnabled bool
CouponCodeSignupUIEnabled bool
FileBrowserFlowDisabled bool
LinksharingURL string
PathwayOverviewEnabled bool
RegistrationRecaptchaEnabled bool
RegistrationRecaptchaSiteKey string
RegistrationHcaptchaEnabled bool
RegistrationHcaptchaSiteKey string
LoginRecaptchaEnabled bool
LoginRecaptchaSiteKey string
LoginHcaptchaEnabled bool
LoginHcaptchaSiteKey string
NewProjectDashboard bool
DefaultPaidStorageLimit memory.Size
DefaultPaidBandwidthLimit memory.Size
NewBillingScreen bool
InactivityTimerEnabled bool
InactivityTimerDuration int
InactivityTimerViewerEnabled bool
OptionalSignupSuccessURL string
HomepageURL string
NativeTokenPaymentsEnabled bool
NewEncryptionPassphraseFlowEnabled bool
PasswordMinimumLength int
PasswordMaximumLength int
ABTestingEnabled bool
ExternalAddress string
SatelliteName string
SatelliteNodeURL string
StripePublicKey string
PartneredSatellites string
DefaultProjectLimit int
GeneralRequestURL string
ProjectLimitsIncreaseRequestURL string
GatewayCredentialsRequestURL string
IsBetaSatellite bool
BetaSatelliteFeedbackURL string
BetaSatelliteSupportURL string
DocumentationURL string
CouponCodeBillingUIEnabled bool
CouponCodeSignupUIEnabled bool
FileBrowserFlowDisabled bool
LinksharingURL string
PathwayOverviewEnabled bool
RegistrationRecaptchaEnabled bool
RegistrationRecaptchaSiteKey string
RegistrationHcaptchaEnabled bool
RegistrationHcaptchaSiteKey string
LoginRecaptchaEnabled bool
LoginRecaptchaSiteKey string
LoginHcaptchaEnabled bool
LoginHcaptchaSiteKey string
NewProjectDashboard bool
DefaultPaidStorageLimit memory.Size
DefaultPaidBandwidthLimit memory.Size
NewBillingScreen bool
InactivityTimerEnabled bool
InactivityTimerDuration int
InactivityTimerViewerEnabled bool
OptionalSignupSuccessURL string
HomepageURL string
NativeTokenPaymentsEnabled bool
PasswordMinimumLength int
PasswordMaximumLength int
ABTestingEnabled bool
}
data.ExternalAddress = server.config.ExternalAddress
@ -506,7 +504,6 @@ func (server *Server) appHandler(w http.ResponseWriter, r *http.Request) {
data.OptionalSignupSuccessURL = server.config.OptionalSignupSuccessURL
data.HomepageURL = server.config.HomepageURL
data.NativeTokenPaymentsEnabled = server.config.NativeTokenPaymentsEnabled
data.NewEncryptionPassphraseFlowEnabled = server.config.NewEncryptionPassphraseFlowEnabled
data.PasswordMinimumLength = console.PasswordMinimumLength
data.PasswordMaximumLength = console.PasswordMaximumLength
data.ABTestingEnabled = server.config.ABTesting.Enabled

View File

@ -244,9 +244,6 @@ compensation.withheld-percents: 75,75,75,50,50,50,25,25,25,0,0,0,0,0,0
# indicates if new billing screens should be used
# console.new-billing-screen: true
# indicates if new encryption passphrase flow is enabled
# console.new-encryption-passphrase-flow-enabled: true
# indicates if new project dashboard should be used
# console.new-project-dashboard: true

View File

@ -38,7 +38,6 @@
<meta name="optional-signup-success-url" content="{{ .OptionalSignupSuccessURL }}">
<meta name="homepage-url" content="{{ .HomepageURL }}">
<meta name="native-token-payments-enabled" content="{{ .NativeTokenPaymentsEnabled }}">
<meta name="new-encryption-passphrase-flow-enabled" content="{{ .NewEncryptionPassphraseFlowEnabled }}">
<meta name="password-minimum-length" content="{{ .PasswordMinimumLength }}">
<meta name="password-maximum-length" content="{{ .PasswordMaximumLength }}">
<meta name="ab-testing-enabled" content="{{ .ABTestingEnabled }}">

View File

@ -40,7 +40,6 @@ export default class App extends Vue {
const couponCodeBillingUIEnabled = MetaUtils.getMetaContent('coupon-code-billing-ui-enabled');
const couponCodeSignupUIEnabled = MetaUtils.getMetaContent('coupon-code-signup-ui-enabled');
const isNewProjectDashboard = MetaUtils.getMetaContent('new-project-dashboard');
const isNewEncryptionPassphraseFlowEnabled = MetaUtils.getMetaContent('new-encryption-passphrase-flow-enabled');
if (satelliteName) {
this.$store.dispatch(APP_STATE_ACTIONS.SET_SATELLITE_NAME, satelliteName);
@ -73,10 +72,6 @@ export default class App extends Vue {
this.$store.dispatch(APP_STATE_ACTIONS.SET_PROJECT_DASHBOARD_STATUS, isNewProjectDashboard === 'true');
}
if (isNewEncryptionPassphraseFlowEnabled) {
this.$store.dispatch(APP_STATE_ACTIONS.SET_ENCRYPTION_PASSPHRASE_FLOW_STATUS, isNewEncryptionPassphraseFlowEnabled === 'true');
}
this.fixViewportHeight();
}

View File

@ -5,28 +5,11 @@
<VModal :on-close="closeModal">
<template #content>
<div class="modal">
<template v-if="isNewEncryptionPassphraseFlowEnabled">
<OpenBucketIcon />
<h1 class="modal__title">Enter your encryption passphrase</h1>
<p class="modal__info">
To open a bucket and view your encrypted files, <br>please enter your encryption passphrase.
</p>
</template>
<template v-else>
<Icon />
<h1 class="modal__title">Open a Bucket</h1>
<p class="modal__info">
To open a bucket and view your files, please enter the encryption passphrase you saved upon
creating this bucket.
</p>
<VInput
class="modal__input"
label="Bucket Name"
:init-value="bucketName"
role-description="bucket"
:disabled="true"
/>
</template>
<OpenBucketIcon />
<h1 class="modal__title">Enter your encryption passphrase</h1>
<p class="modal__info">
To open a bucket and view your encrypted files, <br>please enter your encryption passphrase.
</p>
<VInput
label="Encryption Passphrase"
placeholder="Enter a passphrase here"
@ -73,7 +56,6 @@ import VModal from '@/components/common/VModal.vue';
import VInput from '@/components/common/VInput.vue';
import VButton from '@/components/common/VButton.vue';
import Icon from '@/../static/images/objects/openBucket.svg';
import OpenBucketIcon from '@/../static/images/buckets/openBucket.svg';
// @vue/component
@ -82,7 +64,6 @@ import OpenBucketIcon from '@/../static/images/buckets/openBucket.svg';
VInput,
VModal,
VButton,
Icon,
OpenBucketIcon,
},
})
@ -144,11 +125,6 @@ export default class OpenBucketModal extends Vue {
const now = new Date();
const inThreeDays = new Date(now.setDate(now.getDate() + 3));
let bucketsCaveat: string[] = [];
if (!this.isNewEncryptionPassphraseFlowEnabled) {
bucketsCaveat = this.bucketName ? [this.bucketName] : [];
}
await this.worker.postMessage({
'type': 'SetPermission',
'isDownload': true,
@ -156,7 +132,7 @@ export default class OpenBucketModal extends Vue {
'isList': true,
'isDelete': true,
'notAfter': inThreeDays.toISOString(),
'buckets': bucketsCaveat,
'buckets': [],
'apiKey': this.apiKey,
});
@ -185,11 +161,8 @@ export default class OpenBucketModal extends Vue {
const gatewayCredentials: EdgeCredentials = await this.$store.dispatch(ACCESS_GRANTS_ACTIONS.GET_GATEWAY_CREDENTIALS, { accessGrant });
await this.$store.dispatch(OBJECTS_ACTIONS.SET_GATEWAY_CREDENTIALS, gatewayCredentials);
if (this.isNewEncryptionPassphraseFlowEnabled) {
await this.$store.dispatch(OBJECTS_ACTIONS.SET_S3_CLIENT);
await this.$store.commit(OBJECTS_MUTATIONS.SET_PROMPT_FOR_PASSPHRASE, false);
}
await this.$store.dispatch(OBJECTS_ACTIONS.SET_S3_CLIENT);
await this.$store.commit(OBJECTS_MUTATIONS.SET_PROMPT_FOR_PASSPHRASE, false);
}
/**
@ -234,13 +207,6 @@ export default class OpenBucketModal extends Vue {
private get apiKey(): string {
return this.$store.state.objectsModule.apiKey;
}
/**
* Indicates if new encryption passphrase flow is enabled.
*/
public get isNewEncryptionPassphraseFlowEnabled(): boolean {
return this.$store.state.appStateModule.isNewEncryptionPassphraseFlowEnabled;
}
}
</script>
@ -273,10 +239,6 @@ export default class OpenBucketModal extends Vue {
margin-bottom: 32px;
}
&__input {
margin-bottom: 21px;
}
&__buttons {
display: flex;
column-gap: 20px;

View File

@ -47,7 +47,7 @@
<p class="project-selection__dropdown__items__choice__unselected">{{ project.name }}</p>
</div>
</div>
<div v-if="isNewEncryptionPassphraseFlowEnabled" tabindex="0" class="project-selection__dropdown__link-container" @click.stop="onManagePassphraseClick" @keyup.enter="onManagePassphraseClick">
<div tabindex="0" class="project-selection__dropdown__link-container" @click.stop="onManagePassphraseClick" @keyup.enter="onManagePassphraseClick">
<PassphraseIcon />
<p class="project-selection__dropdown__link-container__label">Manage Passphrase</p>
</div>
@ -346,20 +346,9 @@ export default class MobileNavigation extends Vue {
* Toggles manage passphrase modal shown.
*/
public onManagePassphraseClick(): void {
if (!this.isNewEncryptionPassphraseFlowEnabled) {
return;
}
this.$store.commit(APP_STATE_MUTATIONS.TOGGLE_MANAGE_PROJECT_PASSPHRASE_MODAL_SHOWN);
}
/**
* Indicates if new encryption passphrase flow is enabled.
*/
public get isNewEncryptionPassphraseFlowEnabled(): boolean {
return this.$store.state.appStateModule.isNewEncryptionPassphraseFlowEnabled;
}
/**
* Indicates if current route is objects view.
*/

View File

@ -39,7 +39,7 @@
<p class="project-selection__dropdown__items__choice__unselected">{{ project.name }}</p>
</div>
</div>
<div v-if="isNewEncryptionPassphraseFlowEnabled" tabindex="0" class="project-selection__dropdown__link-container" @click.stop="onManagePassphraseClick" @keyup.enter="onManagePassphraseClick">
<div tabindex="0" class="project-selection__dropdown__link-container" @click.stop="onManagePassphraseClick" @keyup.enter="onManagePassphraseClick">
<PassphraseIcon />
<p class="project-selection__dropdown__link-container__label">Manage Passphrase</p>
</div>
@ -152,11 +152,8 @@ export default class ProjectSelection extends Vue {
await this.$store.dispatch(PM_ACTIONS.SET_SEARCH_QUERY, '');
this.closeDropdown();
if (this.isNewEncryptionPassphraseFlowEnabled || this.isBucketsView) {
this.$store.commit(OBJECTS_MUTATIONS.CLEAR);
}
if (this.isBucketsView) {
this.$store.commit(OBJECTS_MUTATIONS.CLEAR);
await this.$router.push(RouteConfig.Buckets.path).catch(() => {return; });
return;
@ -266,10 +263,6 @@ export default class ProjectSelection extends Vue {
* Toggles manage passphrase modal shown.
*/
public onManagePassphraseClick(): void {
if (!this.isNewEncryptionPassphraseFlowEnabled) {
return;
}
this.$store.commit(APP_STATE_MUTATIONS.TOGGLE_MANAGE_PROJECT_PASSPHRASE_MODAL_SHOWN);
this.closeDropdown();
@ -296,13 +289,6 @@ export default class ProjectSelection extends Vue {
this.closeDropdown();
}
/**
* Indicates if new encryption passphrase flow is enabled.
*/
public get isNewEncryptionPassphraseFlowEnabled(): boolean {
return this.$store.state.appStateModule.isNewEncryptionPassphraseFlowEnabled;
}
/**
* Indicates if current route is objects view.
*/

View File

@ -1,286 +0,0 @@
// Copyright (C) 2022 Storj Labs, Inc.
// See LICENSE for copying information.
<template>
<div class="bucket-creation">
<bucket-creation-progress class="bucket-creation__progress" :creation-step="creationStep" />
<bucket-creation-name-step
v-if="creationStep === BucketCreationSteps.Name"
:is-parent-loading="isLoading"
@setName="setName"
/>
<bucket-creation-generate-passphrase
v-if="creationStep === BucketCreationSteps.Passphrase"
:on-next-click="onPassphraseGenerationNextClick"
:on-back-click="onGenerationBackClick"
:set-parent-passphrase="setPassphrase"
:is-loading="isLoading"
/>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import { RouteConfig } from '@/router';
import { OBJECTS_ACTIONS, OBJECTS_MUTATIONS } from '@/store/modules/objects';
import { AccessGrant, EdgeCredentials } from '@/types/accessGrants';
import { ACCESS_GRANTS_ACTIONS } from '@/store/modules/accessGrants';
import { PROJECTS_ACTIONS } from '@/store/modules/projects';
import { MetaUtils } from '@/utils/meta';
import { AnalyticsHttpApi } from '@/api/analytics';
import { AnalyticsErrorEventSource, AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
import { BUCKET_ACTIONS } from '@/store/modules/buckets';
import BucketCreationGeneratePassphrase from '@/components/objects/BucketCreationGeneratePassphrase.vue';
import BucketCreationNameStep from '@/components/objects/BucketCreationNameStep.vue';
import BucketCreationProgress from '@/components/objects/BucketCreationProgress.vue';
export enum BucketCreationSteps {
Name = 0,
Passphrase,
Upload
}
// @vue/component
@Component({
components: {
BucketCreationProgress,
BucketCreationNameStep,
BucketCreationGeneratePassphrase,
},
})
export default class BucketCreation extends Vue {
private worker: Worker;
private readonly FILE_BROWSER_AG_NAME: string = 'Web file browser API key';
public readonly BucketCreationSteps = BucketCreationSteps;
public creationStep: BucketCreationSteps = BucketCreationSteps.Name;
public isLoading = false;
public bucketName = '';
public passphrase = '';
public readonly analytics: AnalyticsHttpApi = new AnalyticsHttpApi();
/**
* Sets bucket name from child component.
*/
public async setName(name: string): Promise<void> {
this.bucketName = name;
if (this.isNewEncryptionPassphraseFlowEnabled && !this.promptForPassphrase) {
this.isLoading = true;
try {
await this.createBucketAndNavigate();
} catch (error) {
await this.$notify.error(error.message, AnalyticsErrorEventSource.BUCKET_CREATION_FLOW);
}
this.isLoading = false;
return;
}
this.creationStep = BucketCreationSteps.Passphrase;
}
/**
* Sets passphrase from child component.
*/
public setPassphrase(passphrase: string): void {
this.passphrase = passphrase;
this.$store.dispatch(OBJECTS_ACTIONS.SET_PASSPHRASE, this.passphrase);
}
/**
* Sets local worker with worker instantiated in store.
*/
public setWorker(): void {
this.worker = this.$store.state.accessGrantsModule.accessGrantsWebWorker;
this.worker.onerror = (error: ErrorEvent) => {
this.$notify.error(error.message, AnalyticsErrorEventSource.BUCKET_CREATION_FLOW);
};
}
/**
* Holds on next button click logic on passphrase generation step.
*/
public async onPassphraseGenerationNextClick(): Promise<void> {
if (this.isLoading) return;
this.isLoading = true;
try {
this.setWorker();
await this.setAccess();
await this.createBucketAndNavigate();
} catch (error) {
await this.$notify.error(error.message, AnalyticsErrorEventSource.BUCKET_CREATION_FLOW);
} finally {
this.isLoading = false;
}
}
/**
* Holds on back button click logic on passphrase generation step.
*/
public onGenerationBackClick(): void {
this.creationStep = BucketCreationSteps.Name;
}
/**
* Removes temporary created access grant.
*/
public async removeTemporaryAccessGrant(): Promise<void> {
try {
await this.$store.dispatch(ACCESS_GRANTS_ACTIONS.DELETE_BY_NAME_AND_PROJECT_ID, this.FILE_BROWSER_AG_NAME);
} catch (error) {
await this.$notify.error(error.message, AnalyticsErrorEventSource.BUCKET_CREATION_FLOW);
}
}
/**
* Fetches bucket using api.
*/
public async fetchBuckets(page = 1): Promise<void> {
try {
await this.$store.dispatch(BUCKET_ACTIONS.FETCH, page);
} catch (error) {
await this.$notify.error(`Unable to fetch buckets. ${error.message}`, AnalyticsErrorEventSource.BUCKET_CREATION_FLOW);
}
}
/**
* Sets access to S3 client.
*/
public async setAccess(): Promise<void> {
if (!this.apiKey) {
await this.removeTemporaryAccessGrant();
const cleanAPIKey: AccessGrant = await this.$store.dispatch(ACCESS_GRANTS_ACTIONS.CREATE, this.FILE_BROWSER_AG_NAME);
await this.$store.dispatch(OBJECTS_ACTIONS.SET_API_KEY, cleanAPIKey.secret);
}
const now = new Date();
const inThreeDays = new Date(now.setDate(now.getDate() + 3));
const bucketsCaveat: string[] = [];
if (!this.isNewEncryptionPassphraseFlowEnabled) {
bucketsCaveat.push(this.bucketName);
}
await this.worker.postMessage({
'type': 'SetPermission',
'isDownload': true,
'isUpload': true,
'isList': true,
'isDelete': true,
'notAfter': inThreeDays.toISOString(),
'buckets': bucketsCaveat,
'apiKey': this.apiKey,
});
const grantEvent: MessageEvent = await new Promise(resolve => this.worker.onmessage = resolve);
if (grantEvent.data.error) {
throw new Error(grantEvent.data.error);
}
const satelliteNodeURL: string = MetaUtils.getMetaContent('satellite-nodeurl');
const salt = await this.$store.dispatch(PROJECTS_ACTIONS.GET_SALT, this.$store.getters.selectedProject.id);
this.worker.postMessage({
'type': 'GenerateAccess',
'apiKey': grantEvent.data.value,
'passphrase': this.passphrase,
'salt': salt,
'satelliteNodeURL': satelliteNodeURL,
});
const accessGrantEvent: MessageEvent = await new Promise(resolve => this.worker.onmessage = resolve);
if (accessGrantEvent.data.error) {
throw new Error(accessGrantEvent.data.error);
}
const accessGrant = accessGrantEvent.data.value;
const gatewayCredentials: EdgeCredentials = await this.$store.dispatch(ACCESS_GRANTS_ACTIONS.GET_GATEWAY_CREDENTIALS, { accessGrant });
await this.$store.dispatch(OBJECTS_ACTIONS.SET_GATEWAY_CREDENTIALS, gatewayCredentials);
await this.$store.dispatch(OBJECTS_ACTIONS.SET_S3_CLIENT);
if (this.isNewEncryptionPassphraseFlowEnabled) {
await this.$store.commit(OBJECTS_MUTATIONS.SET_PROMPT_FOR_PASSPHRASE, false);
}
}
/**
* Creates bucket and navigates to file browser.
*/
private async createBucketAndNavigate(): Promise<void> {
await this.$store.dispatch(OBJECTS_ACTIONS.CREATE_BUCKET, this.bucketName);
await this.fetchBuckets();
await this.$store.dispatch(OBJECTS_ACTIONS.SET_FILE_COMPONENT_BUCKET_NAME, this.bucketName);
this.analytics.eventTriggered(AnalyticsEvent.BUCKET_CREATED);
this.analytics.pageVisit(RouteConfig.UploadFile.path);
await this.$router.push(RouteConfig.UploadFile.path);
}
/**
* Returns apiKey from store.
*/
private get apiKey(): string {
return this.$store.state.objectsModule.apiKey;
}
/**
* Indicates if new encryption passphrase flow is enabled.
*/
public get isNewEncryptionPassphraseFlowEnabled(): boolean {
return this.$store.state.appStateModule.isNewEncryptionPassphraseFlowEnabled;
}
/**
* Returns condition if user has to be prompt for passphrase from store.
*/
private get promptForPassphrase(): boolean {
return this.$store.state.objectsModule.promptForPassphrase;
}
}
</script>
<style scoped lang="scss">
.bucket-creation {
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
font-family: 'font_regular', sans-serif;
padding-bottom: 30px;
&__progress {
margin-bottom: 44px;
width: 460px;
@media screen and (max-width: 760px) {
width: 85%;
}
}
}
:deep(.bucket-icon) {
width: 267px;
}
@media screen and (max-width: 760px) {
:deep(.label-container__main__label) {
font-size: 0.875rem !important;
line-height: 1.285rem !important;
}
}
@media screen and (max-width: 600px) {
:deep(.bucket-icon) {
width: 190px;
}
}
</style>

View File

@ -1,455 +0,0 @@
// Copyright (C) 2022 Storj Labs, Inc.
// See LICENSE for copying information.
<template>
<div class="encrypt-container">
<bucket-icon class="bucket-icon" />
<div v-if="generationStep === GenerationSteps.TypeSelection" class="encrypt-container__functional">
<div class="encrypt-container__functional__header">
<p class="encrypt-container__functional__header__title" aria-roledescription="title">
Encrypt your bucket
</p>
<p class="encrypt-container__functional__header__info">
We encourage you to generate the encryption passphrase.
You can also enter your own passphrase for this bucket.
</p>
</div>
<div class="encrypt-container__functional__variant" aria-roledescription="generate" @click="selectedType = GenerationSteps.Generation">
<input
class="encrypt-container__functional__variant__radio"
type="radio"
name="radio"
:checked="selectedType === GenerationSteps.Generation"
>
<div class="encrypt-container__functional__variant__icon">
<key-icon />
</div>
<div class="encrypt-container__functional__variant__text-container">
<h4 class="encrypt-container__functional__variant__text-container__title">Generate passphrase</h4>
<p class="encrypt-container__functional__variant__text-container__info">Automatically generate 12-word passphrase.</p>
</div>
</div>
<div class="encrypt-container__functional__variant__divider" />
<div class="encrypt-container__functional__variant" aria-roledescription="manual" @click="selectedType = GenerationSteps.Manual">
<input
class="encrypt-container__functional__variant__radio"
type="radio"
name="radio"
:checked="selectedType === GenerationSteps.Manual"
>
<div class="encrypt-container__functional__variant__icon">
<fingerprint-icon />
</div>
<div class="encrypt-container__functional__variant__text-container">
<h4 class="encrypt-container__functional__variant__text-container__title">Enter passphrase</h4>
<p class="encrypt-container__functional__variant__text-container__info">You can also enter your own passphrase.</p>
</div>
</div>
</div>
<div v-else class="encrypt-container__functional">
<div class="encrypt-container__functional__header">
<p class="encrypt-container__functional__header__title" aria-roledescription="title">
{{ generationStep === GenerationSteps.Generation ? 'Generate a passphrase' : 'Enter a passphrase' }}
</p>
<p class="encrypt-container__functional__header__info">
Please note that Storj does not know or store your encryption passphrase.
If you lose it, you will not be able to recover your files.
</p>
</div>
<div v-if="generationStep === GenerationSteps.Generation" class="encrypt-container__functional__generate">
<p class="encrypt-container__functional__generate__value" aria-roledescription="mnemonic">{{ passphrase }}</p>
<v-button
class="encrypt-container__functional__generate__button"
label="Download"
width="143px"
height="48px"
:on-press="onDownloadClick"
/>
</div>
<div v-else class="encrypt-container__functional__enter">
<v-input
label="Your Passphrase"
placeholder="Enter a passphrase here..."
:error="enterError"
role-description="passphrase"
is-password
:disabled="isLoading"
@setData="setPassphrase"
/>
</div>
<v-checkbox
class="encrypt-container__functional__checkbox"
label="I understand, and I have saved the passphrase."
:is-checkbox-error="isCheckboxError"
@setData="setSavingConfirmation"
/>
</div>
<div class="encrypt-container__buttons">
<v-button
class="encrypt-container__buttons__back button"
label="Back"
height="48px"
width="45%"
:is-white="true"
:on-press="generationStep === GenerationSteps.TypeSelection ? onBackClick : navigateToTypeSelection"
:is-disabled="isLoading"
/>
<v-button
v-if="generationStep === GenerationSteps.TypeSelection"
class="button"
height="48px"
width="45%"
label="Continue"
:on-press="selectPassphraseVariant"
/>
<v-button
v-else
class="button"
label="Continue"
height="48px"
width="45%"
:on-press="onNextButtonClick"
:is-disabled="isLoading || !isSavingConfirmed"
/>
</div>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import { generateMnemonic } from 'bip39';
import { Download } from '@/utils/download';
import { AnalyticsHttpApi } from '@/api/analytics';
import { AnalyticsErrorEventSource } from '@/utils/constants/analyticsEventNames';
import VButton from '@/components/common/VButton.vue';
import VInput from '@/components/common/VInput.vue';
import VCheckbox from '@/components/common/VCheckbox.vue';
import BucketIcon from '@/../static/images/objects/bucketCreation.svg';
import KeyIcon from '@/../static/images/objects/key.svg';
import FingerprintIcon from '@/../static/images/objects/fingerprint.svg';
enum GenerationSteps {
TypeSelection,
Generation,
Manual,
}
// @vue/component
@Component({
components: {
BucketIcon,
KeyIcon,
FingerprintIcon,
VButton,
VInput,
VCheckbox,
},
})
export default class GeneratePassphrase extends Vue {
@Prop({ default: () => null })
public readonly onNextClick: () => unknown;
@Prop({ default: () => null })
public readonly onBackClick: () => unknown;
@Prop({ default: () => null })
public readonly setParentPassphrase: (passphrase: string) => void;
@Prop({ default: false })
public readonly isLoading: boolean;
public readonly GenerationSteps = GenerationSteps;
public selectedType: GenerationSteps = GenerationSteps.Generation;
public generationStep: GenerationSteps = GenerationSteps.TypeSelection;
public enterError = '';
public passphrase = '';
public isSavingConfirmed = false;
public isCheckboxError = false;
private readonly analytics = new AnalyticsHttpApi();
public setSavingConfirmation(value: boolean): void {
this.isSavingConfirmed = value;
}
/**
* Selects passphrase setup variant.
* If not manual, generates passphrase.
*/
public selectPassphraseVariant(): void {
if (this.selectedType === GenerationSteps.Generation) {
this.passphrase = generateMnemonic();
this.setParentPassphrase(this.passphrase);
}
this.generationStep = this.selectedType;
}
/**
* Holds on download button click logic.
* Downloads encryption passphrase as a txt file.
*/
public onDownloadClick(): void {
if (!this.passphrase) {
this.enterError = 'Can\'t be empty!';
this.analytics.errorEventTriggered(AnalyticsErrorEventSource.BUCKET_CREATION_PASSPHRASE_STEP);
return;
}
const fileName = 'StorjEncryptionPassphrase.txt';
Download.file(this.passphrase, fileName);
}
/**
* Navigates back to passphrase option selection.
*/
public navigateToTypeSelection(): void {
this.enterError = '';
this.passphrase = '';
this.isSavingConfirmed = false;
this.generationStep = GenerationSteps.TypeSelection;
}
/**
* Sets passphrase from child component.
*/
public setPassphrase(passphrase: string): void {
if (this.enterError) this.enterError = '';
this.passphrase = passphrase;
this.setParentPassphrase(this.passphrase);
}
/**
* Holds on next button click logic.
*/
public async onNextButtonClick(): Promise<void> {
if (!this.passphrase) {
this.enterError = 'Can\'t be empty!';
this.analytics.errorEventTriggered(AnalyticsErrorEventSource.BUCKET_CREATION_PASSPHRASE_STEP);
return;
}
if (!this.isSavingConfirmed) {
this.isCheckboxError = true;
this.analytics.errorEventTriggered(AnalyticsErrorEventSource.BUCKET_CREATION_PASSPHRASE_STEP);
return;
}
await this.onNextClick();
}
}
</script>
<style lang="scss">
.encrypt-container {
font-family: 'font_regular', sans-serif;
padding: 60px 60px 50px;
max-width: 500px;
background: #fcfcfc;
box-shadow: 0 0 32px rgb(0 0 0 / 4%);
border-radius: 20px;
margin: 30px auto 0;
display: flex;
flex-direction: column;
align-items: center;
&__functional {
margin-top: 20px;
&__header {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
padding: 25px 0;
text-align: center;
&__title {
font-family: 'font_bold', sans-serif;
font-size: 26px;
line-height: 31px;
color: #131621;
margin-bottom: 15px;
}
&__info {
font-family: 'font_regular', sans-serif;
font-size: 16px;
line-height: 21px;
color: #354049;
}
}
&__variant {
display: flex;
align-items: center;
justify-content: flex-start;
padding: 20px 0;
cursor: pointer;
&__radio {
color: var(--c-blue-3);
}
&__icon {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
border-radius: 50%;
background: var(--c-blue-1);
margin: 0 8px;
svg {
width: 16px;
height: 16px;
max-width: 16px;
max-height: 16px;
}
}
&__text-container {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: flex-start;
width: 100%;
&__title {
font-family: 'font_bold', sans-serif;
font-size: 14px;
line-height: 20px;
color: #000;
}
&__info {
font-family: 'font_regular', sans-serif;
font-size: 12px;
line-height: 18px;
color: #000;
}
}
&__divider {
height: 1px;
width: 100%;
background: var(--c-grey-4);
}
}
&__generate {
display: flex;
align-items: center;
padding: 16px 22px;
background: #eff0f7;
border-radius: 10px;
margin-top: 25px;
&__value {
font-size: 14px;
line-height: 25px;
color: #384b65;
}
&__button {
margin-left: 12px;
min-width: 130px;
}
}
&__download {
font-family: 'font_bold', sans-serif;
font-size: 16px;
line-height: 19px;
color: #0068dc;
cursor: pointer;
margin: 20px 25px;
display: inline-block;
}
&__warning-title {
font-family: 'font_bold', sans-serif;
font-size: 16px;
line-height: 19px;
color: #1b2533;
margin: 25px 25px 10px;
}
&__warning-msg {
font-size: 14px;
line-height: 20px;
color: #1b2533;
margin: 0 25px;
}
&__checkbox {
margin-top: 25px;
}
}
&__buttons {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 30px;
&__back {
margin-right: 24px;
}
}
}
@media screen and (max-width: 760px) {
.encrypt-container {
padding: 40px 32px;
}
}
@media screen and (max-width: 600px) {
.encrypt-container {
&__functional__header {
&__title {
font-size: 1.715rem;
line-height: 2.215rem;
}
&__info {
font-size: 0.875rem;
line-height: 1.285rem;
}
}
&__buttons {
flex-direction: column-reverse;
margin-top: 25px;
.button {
width: 100% !important;
&:first-of-type {
margin: 25px 0 0;
}
}
}
}
}
@media screen and (max-width: 385px) {
.encrypt-container {
padding: 20px;
}
}
</style>

View File

@ -1,264 +0,0 @@
// Copyright (C) 2022 Storj Labs, Inc.
// See LICENSE for copying information.
<template>
<div class="bucket-name-creation">
<v-loader v-if="isLoading" width="100px" height="100px" />
<template v-else>
<bucket-icon class="bucket-icon" />
<div class="bucket-name-creation__functional">
<div class="bucket-name-creation__functional__header">
<p class="bucket-name-creation__functional__header__title" aria-roledescription="title">
Create a bucket
</p>
<p class="bucket-name-creation__functional__header__info">
Buckets are used to store your files. Its recommended that every bucket should have its own encryption passphrase.
</p>
</div>
<v-input
label="Bucket Name"
placeholder="Enter a name here..."
:error="nameError"
role-description="name"
:init-value="name"
additional-label="Lowercase alphanumeric characters only (no spaces)"
:disabled="isLoading || isParentLoading"
@setData="onChangeName"
/>
</div>
<div class="bucket-name-creation__buttons">
<v-button
class="button"
label="Cancel"
height="48px"
width="47%"
:on-press="onCancelClick"
:is-white="true"
/>
<v-button
class="button"
label="Continue"
height="48px"
width="47%"
:on-press="onNextButtonClick"
:is-disabled="!name || nameError !== '' || isParentLoading"
/>
</div>
</template>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import { RouteConfig } from '@/router';
import { Validator } from '@/utils/validation';
import { LocalData } from '@/utils/localData';
import { BUCKET_ACTIONS } from '@/store/modules/buckets';
import { AnalyticsHttpApi } from '@/api/analytics';
import { AnalyticsErrorEventSource } from '@/utils/constants/analyticsEventNames';
import VInput from '@/components/common/VInput.vue';
import VButton from '@/components/common/VButton.vue';
import VLoader from '@/components/common/VLoader.vue';
import BucketIcon from '@/../static/images/objects/bucketCreation.svg';
// @vue/component
@Component({
components: {
VInput,
VButton,
BucketIcon,
VLoader,
},
})
export default class BucketCreationNameStep extends Vue {
@Prop({ default: false })
public readonly isParentLoading: boolean;
public name = '';
public nameError = '';
public isLoading = true;
public readonly analytics: AnalyticsHttpApi = new AnalyticsHttpApi();
public async mounted(): Promise<void> {
try {
await this.$store.dispatch(BUCKET_ACTIONS.FETCH_ALL_BUCKET_NAMES);
this.name = this.allBucketNames.length > 0 ? '' : 'demo-bucket';
} catch (error) {
await this.$notify.error(error.message, AnalyticsErrorEventSource.BUCKET_CREATION_NAME_STEP);
} finally {
this.isLoading = false;
}
}
/**
* Sets bucket name from input.
*/
public onChangeName(value: string): void {
if (this.nameError) this.nameError = '';
this.name = value;
}
/**
* Sets bucket name from input.
*/
public onNextButtonClick(): void {
if (!this.isBucketNameValid(this.name)) {
this.analytics.errorEventTriggered(AnalyticsErrorEventSource.BUCKET_CREATION_NAME_STEP);
return;
}
if (this.allBucketNames.includes(this.name)) {
this.$notify.error('Bucket with this name already exists', AnalyticsErrorEventSource.BUCKET_CREATION_NAME_STEP);
return;
}
this.$emit('setName', this.name);
}
/**
* Redirects to buckets list view.
*/
public onCancelClick(): void {
LocalData.setDemoBucketCreatedStatus();
this.analytics.pageVisit(RouteConfig.Buckets.with(RouteConfig.BucketsManagement).path);
this.$router.push(RouteConfig.Buckets.with(RouteConfig.BucketsManagement).path);
}
/**
* Returns validation status of a bucket name.
*/
private isBucketNameValid(name: string): boolean {
switch (true) {
case name.length < 3 || name.length > 63:
this.nameError = 'Name must be not less than 3 and not more than 63 characters length';
return false;
case !Validator.bucketName(name):
this.nameError = 'Name must contain only lowercase latin characters, numbers, a hyphen or a period';
return false;
default:
return true;
}
}
private get allBucketNames(): string[] {
return this.$store.state.bucketUsageModule.allBucketNames;
}
}
</script>
<style scoped lang="scss">
.bucket-name-creation {
font-family: 'font_regular', sans-serif;
padding: 60px 65px 50px;
max-width: 500px;
background: #fcfcfc;
box-shadow: 0 0 32px rgb(0 0 0 / 4%);
border-radius: 20px;
margin: 30px auto 0;
display: flex;
flex-direction: column;
align-items: center;
&__functional {
margin-top: 20px;
&__header {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
padding: 25px 0;
text-align: center;
&__title {
font-family: 'font_bold', sans-serif;
font-size: 26px;
line-height: 31px;
color: #131621;
margin-bottom: 15px;
}
&__info {
font-family: 'font_regular', sans-serif;
font-size: 16px;
line-height: 21px;
color: #354049;
}
}
}
&__buttons {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 30px;
&__back {
margin-right: 24px;
}
}
}
:deep(.label-container__main__label) {
font-size: 14px;
}
:deep(.label-container__main) {
width: 100%;
justify-content: space-between;
}
@media screen and (max-width: 760px) {
.bucket-name-creation {
padding: 40px 32px;
}
}
@media screen and (max-width: 600px) {
.bucket-name-creation {
&__functional__header {
&__title {
font-size: 1.715rem;
line-height: 2.215rem;
}
&__info {
font-size: 0.875rem;
line-height: 1.285rem;
}
}
&__buttons {
flex-direction: column-reverse;
margin-top: 25px;
.button {
width: 100% !important;
&:first-of-type {
margin: 25px 0 0;
}
}
}
}
}
@media screen and (max-width: 385px) {
.bucket-name-creation {
padding: 20px;
}
}
</style>

View File

@ -1,138 +0,0 @@
// Copyright (C) 2022 Storj Labs, Inc.
// See LICENSE for copying information.
<template>
<div class="bucket-creation-progress">
<div class="bucket-creation-progress__item active">
<div class="bucket-creation-progress__item__outer-circle">
<div class="bucket-creation-progress__item__inner-circle">
<span v-if="creationStep === BucketCreationSteps.Name">1</span>
<check-icon v-else />
</div>
</div>
<h4 class="bucket-creation-progress__item__label" :class="{ passed: creationStep >= BucketCreationSteps.Passphrase }">Bucket</h4>
<div class="bucket-creation-progress__item__divider" />
</div>
<div class="bucket-creation-progress__item" :class="{ active: creationStep >= BucketCreationSteps.Passphrase }">
<div class="bucket-creation-progress__item__outer-circle">
<div class="bucket-creation-progress__item__inner-circle">
<check-icon v-if="creationStep === BucketCreationSteps.Upload" />
<span v-else>2</span>
</div>
</div>
<h4 class="bucket-creation-progress__item__label" :class="{ passed: creationStep >= BucketCreationSteps.Passphrase }">Encryption</h4>
<div class="bucket-creation-progress__item__divider" />
</div>
<div class="bucket-creation-progress__item" :class="{ active: creationStep > BucketCreationSteps.Passphrase }">
<div class="bucket-creation-progress__item__outer-circle">
<div class="bucket-creation-progress__item__inner-circle">
<span>3</span>
</div>
</div>
<h4 class="bucket-creation-progress__item__label">Upload</h4>
</div>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import { BucketCreationSteps } from '@/components/objects/BucketCreation.vue';
import CheckIcon from '@/../static/images/objects/check.svg';
// @vue/component
@Component({
components: {
CheckIcon,
},
})
export default class BucketCreationProgress extends Vue {
@Prop({ default: 0 })
public readonly creationStep: BucketCreationSteps;
public readonly BucketCreationSteps = BucketCreationSteps;
}
</script>
<style scoped lang="scss">
.bucket-creation-progress {
display: flex;
align-items: flex-start;
justify-content: space-between;
&__item {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
&__outer-circle,
&__inner-circle {
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
}
&__outer-circle {
width: 35px;
height: 35px;
background: rgb(20 20 42 / 20%);
}
&__inner-circle {
width: 23px;
height: 23px;
background: #b1b1b1;
span {
font-family: 'font_semiBold', sans-serif;
font-size: 10px;
color: white;
}
}
&__label {
font-family: 'font_bold', sans-serif;
font-size: 16px;
line-height: 19px;
color: rgb(20 20 42 / 20%);
margin-top: 13px;
}
&__divider {
position: absolute;
width: 130px;
height: 1px;
top: 16px;
left: 100%;
background: var(--c-grey-2);
@media screen and (max-width: 760px) {
display: none;
}
}
&.active {
.bucket-creation-progress__item__outer-circle {
background: var(--c-blue-2);
}
.bucket-creation-progress__item__inner-circle {
background: var(--c-blue-3);
}
.bucket-creation-progress__item__label {
color: var(--c-blue-3);
&.passed {
color: #14142a !important;
}
}
}
}
}
</style>

View File

@ -86,10 +86,7 @@ export default class BucketDetails extends Vue {
public openBucket(): void {
this.$store.dispatch(OBJECTS_ACTIONS.SET_FILE_COMPONENT_BUCKET_NAME, this.bucket?.name);
if (
this.$route.params.backRoute === RouteConfig.UploadFileChildren.name ||
(this.isNewEncryptionPassphraseFlowEnabled && !this.promptForPassphrase)
) {
if (this.$route.params.backRoute === RouteConfig.UploadFileChildren.name || !this.promptForPassphrase) {
this.analytics.pageVisit(RouteConfig.Buckets.with(RouteConfig.UploadFile).path);
this.$router.push(RouteConfig.Buckets.with(RouteConfig.UploadFile).path);
@ -105,13 +102,6 @@ export default class BucketDetails extends Vue {
private get promptForPassphrase(): boolean {
return this.$store.state.objectsModule.promptForPassphrase;
}
/**
* Indicates if new encryption passphrase flow is enabled.
*/
private get isNewEncryptionPassphraseFlowEnabled(): boolean {
return this.$store.state.appStateModule.isNewEncryptionPassphraseFlowEnabled;
}
}
</script>

View File

@ -19,28 +19,19 @@
<EmptyBucketIcon class="buckets-table__no-buckets-area__image" />
<CreateBucketIcon class="buckets-table__no-buckets-area__small-image" />
<h4 class="buckets-table__no-buckets-area__title">There are no buckets in this project</h4>
<template v-if="isNewEncryptionPassphraseFlowEnabled">
<template v-if="promptForPassphrase">
<p class="buckets-table__no-buckets-area__body">Set an encryption passphrase to start uploading files.</p>
<VButton
label="Set Encryption Passphrase ->"
width="234px"
height="40px"
font-size="14px"
:on-press="onSetClick"
/>
</template>
<template v-else>
<p class="buckets-table__no-buckets-area__body">Create a new bucket to upload files</p>
<div class="new-bucket-button" :class="{ disabled: isLoading }" @click="onCreateBucketClick">
<WhitePlusIcon class="new-bucket-button__icon" />
<p class="new-bucket-button__label">New Bucket</p>
</div>
</template>
<template v-if="promptForPassphrase">
<p class="buckets-table__no-buckets-area__body">Set an encryption passphrase to start uploading files.</p>
<VButton
label="Set Encryption Passphrase ->"
width="234px"
height="40px"
font-size="14px"
:on-press="onSetClick"
/>
</template>
<template v-else>
<p class="buckets-table__no-buckets-area__body">Create a new bucket to upload files</p>
<div class="new-bucket-button" :class="{ disabled: isLoading }" @click="onNewBucketButtonClick">
<div class="new-bucket-button" :class="{ disabled: isLoading }" @click="onCreateBucketClick">
<WhitePlusIcon class="new-bucket-button__icon" />
<p class="new-bucket-button__label">New Bucket</p>
</div>
@ -164,13 +155,6 @@ const promptForPassphrase = computed((): boolean => {
return store.state.objectsModule.promptForPassphrase;
});
/**
* Indicates if new encryption passphrase flow is enabled.
*/
const isNewEncryptionPassphraseFlowEnabled = computed((): boolean => {
return store.state.appStateModule.isNewEncryptionPassphraseFlowEnabled;
});
/**
* Toggles set passphrase modal visibility.
*/
@ -185,14 +169,6 @@ function onCreateBucketClick(): void {
store.commit(APP_STATE_MUTATIONS.TOGGLE_CREATE_BUCKET_MODAL_SHOWN);
}
/**
* Starts bucket creation flow.
*/
function onNewBucketButtonClick(): void {
analytics.pageVisit(RouteConfig.Buckets.with(RouteConfig.BucketCreation).path);
router.push(RouteConfig.Buckets.with(RouteConfig.BucketCreation).path);
}
/**
* Fetches bucket using api.
*/
@ -240,7 +216,7 @@ function openDropdown(key: number): void {
*/
function openBucket(bucketName: string): void {
store.dispatch(OBJECTS_ACTIONS.SET_FILE_COMPONENT_BUCKET_NAME, bucketName);
if (isNewEncryptionPassphraseFlowEnabled.value && !promptForPassphrase.value) {
if (!promptForPassphrase.value) {
analytics.pageVisit(RouteConfig.Buckets.with(RouteConfig.UploadFile).path);
router.push(RouteConfig.Buckets.with(RouteConfig.UploadFile).path);

View File

@ -5,26 +5,18 @@
<div class="buckets-view">
<div class="buckets-view__title-area">
<h1 class="buckets-view__title-area__title" aria-roledescription="title">Buckets</h1>
<template v-if="isNewEncryptionPassphraseFlowEnabled">
<VButton
v-if="promptForPassphrase"
label="Set Encryption Passphrase ->"
width="234px"
height="40px"
font-size="14px"
:on-press="onSetClick"
/>
<div v-else class="buckets-view-button" :class="{ disabled: isLoading }" @click="onCreateBucketClick">
<WhitePlusIcon class="buckets-view-button__icon" />
<p class="buckets-view-button__label">New Bucket</p>
</div>
</template>
<template v-else>
<div class="buckets-view-button" :class="{ disabled: isLoading }" @click="onNewBucketButtonClick">
<WhitePlusIcon class="buckets-view-button__icon" />
<p class="buckets-view-button__label">New Bucket</p>
</div>
</template>
<VButton
v-if="promptForPassphrase"
label="Set Encryption Passphrase ->"
width="234px"
height="40px"
font-size="14px"
:on-press="onSetClick"
/>
<div v-else class="buckets-view-button" :class="{ disabled: isLoading }" @click="onCreateBucketClick">
<WhitePlusIcon class="buckets-view-button__icon" />
<p class="buckets-view-button__label">New Bucket</p>
</div>
</div>
<div class="buckets-view__divider" />
@ -99,15 +91,8 @@ export default class BucketsView extends Vue {
return;
}
if (!this.bucketsPage.buckets.length && !wasDemoBucketCreated) {
this.analytics.pageVisit(RouteConfig.Buckets.with(RouteConfig.BucketCreation).path);
if (this.isNewEncryptionPassphraseFlowEnabled) {
if (!this.promptForPassphrase) {
this.$store.commit(APP_STATE_MUTATIONS.TOGGLE_CREATE_BUCKET_MODAL_SHOWN);
}
} else {
await this.$router.push(RouteConfig.Buckets.with(RouteConfig.BucketCreation).path);
}
if (!this.bucketsPage.buckets.length && !wasDemoBucketCreated && !this.promptForPassphrase) {
this.$store.commit(APP_STATE_MUTATIONS.TOGGLE_CREATE_BUCKET_MODAL_SHOWN);
}
} catch (error) {
await this.$notify.error(`Failed to setup Buckets view. ${error.message}`, AnalyticsErrorEventSource.BUCKET_PAGE);
@ -141,14 +126,6 @@ export default class BucketsView extends Vue {
this.$store.commit(APP_STATE_MUTATIONS.TOGGLE_CREATE_BUCKET_MODAL_SHOWN);
}
/**
* Starts bucket creation flow.
*/
public onNewBucketButtonClick(): void {
this.analytics.pageVisit(RouteConfig.Buckets.with(RouteConfig.BucketCreation).path);
this.$router.push(RouteConfig.Buckets.with(RouteConfig.BucketCreation).path);
}
/**
* Hides server-side encryption banner.
*/
@ -164,13 +141,6 @@ export default class BucketsView extends Vue {
return this.$store.state.bucketUsageModule.page;
}
/**
* Indicates if new encryption passphrase flow is enabled.
*/
public get isNewEncryptionPassphraseFlowEnabled(): boolean {
return this.$store.state.appStateModule.isNewEncryptionPassphraseFlowEnabled;
}
/**
* Indicates if user should be prompt for passphrase.
*/

View File

@ -32,17 +32,6 @@ export default class ObjectsArea extends Vue {
await this.$router.push(RouteConfig.ProjectDashboard.path);
}
}
/**
* Lifecycle hook before component destroying.
* Clears objects VUEX state.
*/
public beforeDestroy(): void {
// new encryption passphrase flow should not clear passphrase/api key when exiting object browser.
if (!this.$store.state.appStateModule.isNewEncryptionPassphraseFlowEnabled) {
this.$store.dispatch(OBJECTS_ACTIONS.CLEAR);
}
}
}
</script>

View File

@ -11,8 +11,7 @@
<p class="medium">Do you know a bucket can have multiple passphrases?</p>
<p>
If you dont see the objects youre looking for,
<span v-if="isNewEncryptionPassphraseFlowEnabled" class="link" @click="toggleManagePassphrase">try opening the bucket again</span>
<router-link v-else class="link" :to="bucketsManagementPath">try opening the bucket again</router-link>
<span class="link" @click="toggleManagePassphrase">try opening the bucket again</span>
with a different passphrase.
</p>
</template>
@ -51,8 +50,6 @@ export default class UploadFile extends Vue {
private worker: Worker;
private readonly analytics: AnalyticsHttpApi = new AnalyticsHttpApi();
public readonly bucketsManagementPath: string = RouteConfig.Buckets.with(RouteConfig.BucketsManagement).path;
/**
* Lifecycle hook after vue instance was created.
* Initiates file browser.
@ -75,10 +72,6 @@ export default class UploadFile extends Vue {
@Watch('edgeCredentials.secretKey')
public async reinit(): Promise<void> {
if (!this.isNewEncryptionPassphraseFlowEnabled) {
return;
}
if (!this.edgeCredentials.secretKey) {
await this.$router.push(RouteConfig.Buckets.with(RouteConfig.BucketsManagement).path).catch(() => {return;});
return;
@ -257,13 +250,6 @@ export default class UploadFile extends Vue {
private get edgeCredentials(): EdgeCredentials {
return this.$store.state.objectsModule.gatewayCredentials;
}
/**
* Indicates if new encryption passphrase flow is enabled.
*/
public get isNewEncryptionPassphraseFlowEnabled(): boolean {
return this.$store.state.appStateModule.isNewEncryptionPassphraseFlowEnabled;
}
}
</script>

View File

@ -95,14 +95,7 @@ export default class OverviewStep extends Vue {
* Redirects to buckets page.
*/
public onUploadInBrowserClick(): void {
if (this.isNewEncryptionPassphraseFlowEnabled) {
this.$store.commit(APP_STATE_MUTATIONS.TOGGLE_CREATE_PROJECT_PASSPHRASE_MODAL_SHOWN);
return;
}
this.$router.push(RouteConfig.Buckets.path).catch(() => {return; });
this.analytics.linkEventTriggered(AnalyticsEvent.PATH_SELECTED, 'Continue in Browser');
this.analytics.pageVisit(RouteConfig.Buckets.path);
this.$store.commit(APP_STATE_MUTATIONS.TOGGLE_CREATE_PROJECT_PASSPHRASE_MODAL_SHOWN);
}
/**
@ -111,13 +104,6 @@ export default class OverviewStep extends Vue {
private get satelliteName(): string {
return this.$store.state.appStateModule.satelliteName;
}
/**
* Indicates if new encryption passphrase flow is enabled.
*/
private get isNewEncryptionPassphraseFlowEnabled(): boolean {
return this.$store.state.appStateModule.isNewEncryptionPassphraseFlowEnabled;
}
}
</script>

View File

@ -7,40 +7,7 @@
<p class="project-dashboard__message">
Expect a delay of a few hours between network activity and the latest dashboard stats.
</p>
<DashboardFunctionalHeader
v-if="isNewEncryptionPassphraseFlowEnabled"
:loading="isDataFetching || areBucketsFetching"
/>
<template v-else>
<VLoader v-if="isDataFetching" class="project-dashboard__loader" width="100px" height="100px" />
<p v-if="!isDataFetching && limits.objectCount" class="project-dashboard__subtitle" aria-roledescription="with-usage-title">
Your
<span class="project-dashboard__subtitle__value">{{ limits.objectCount }} objects</span>
are stored in
<span class="project-dashboard__subtitle__value">{{ limits.segmentCount }} segments</span>
around the world
</p>
<template v-if="!isDataFetching && !limits.objectCount">
<p class="project-dashboard__subtitle" aria-roledescription="empty-title">
Welcome to Storj :) <br> Youre ready to experience the future of cloud storage
</p>
</template>
<p class="project-dashboard__limits">
<span class="project-dashboard__limits--bold">Storage Limit</span>
per month: {{ limits.storageLimit | bytesToBase10String }} |
<span class="project-dashboard__limits--bold">Bandwidth Limit</span>
per month: {{ limits.bandwidthLimit | bytesToBase10String }}
</p>
<template v-if="!isDataFetching && !limits.objectCount">
<VButton
class="project-dashboard__upload-button"
label="Upload"
width="100px"
height="40px"
:on-press="onUploadClick"
/>
</template>
</template>
<DashboardFunctionalHeader :loading="isDataFetching || areBucketsFetching" />
<div class="project-dashboard__stats-header">
<h2 class="project-dashboard__stats-header__title">Project Stats</h2>
<div class="project-dashboard__stats-header__buttons">
@ -265,7 +232,7 @@ export default class NewProjectDashboard extends Vue {
past.setDate(past.getDate() - 30);
await this.$store.dispatch(PROJECTS_ACTIONS.GET_LIMITS, this.$store.getters.selectedProject.id);
if (this.isNewEncryptionPassphraseFlowEnabled && this.hasJustLoggedIn) {
if (this.hasJustLoggedIn) {
if (this.limits.objectCount > 0) {
this.$store.commit(APP_STATE_MUTATIONS.TOGGLE_ENTER_PASSPHRASE_MODAL_SHOWN);
} else {
@ -332,14 +299,6 @@ export default class NewProjectDashboard extends Vue {
this.$router.push(RouteConfig.CreateProject.path);
}
/**
* Holds on upload button click logic.
*/
public onUploadClick(): void {
this.analytics.pageVisit(RouteConfig.Buckets.path);
this.$router.push(RouteConfig.Buckets.path).catch(() => {return;});
}
/**
* Returns formatted amount.
*/
@ -441,13 +400,6 @@ export default class NewProjectDashboard extends Vue {
return this.$store.state.projectsModule.chartDataBefore;
}
/**
* Indicates if new encryption passphrase flow is enabled.
*/
public get isNewEncryptionPassphraseFlowEnabled(): boolean {
return this.$store.state.appStateModule.isNewEncryptionPassphraseFlowEnabled;
}
/**
* Indicates if user has just logged in.
*/
@ -479,19 +431,6 @@ export default class NewProjectDashboard extends Vue {
background-repeat: no-repeat;
font-family: 'font_regular', sans-serif;
&__limits {
font-size: 14px;
margin-top: 11px;
&--bold {
font-family: 'font_bold', sans-serif;
}
}
&__loader {
display: inline-block;
}
&__title {
font-family: 'font_medium', sans-serif;
font-size: 16px;
@ -506,25 +445,6 @@ export default class NewProjectDashboard extends Vue {
margin: 10px 0 64px;
}
&__subtitle {
font-family: 'font_bold', sans-serif;
font-size: 28px;
line-height: 36px;
letter-spacing: -0.02em;
color: #000;
max-width: 365px;
&__value {
text-decoration: underline;
text-underline-position: under;
text-decoration-color: var(--c-green-3);
}
}
&__upload-button {
margin-top: 16px;
}
&__stats-header {
display: flex;
align-items: center;

View File

@ -43,7 +43,6 @@ import RegistrationSuccess from '@/components/common/RegistrationSuccess.vue';
import SuccessScreen from '@/components/onboardingTour/steps/cliFlow/SuccessScreen.vue';
import AGName from '@/components/onboardingTour/steps/cliFlow/AGName.vue';
import AGPermissions from '@/components/onboardingTour/steps/cliFlow/AGPermissions.vue';
import BucketCreation from '@/components/objects/BucketCreation.vue';
import BucketDetails from '@/components/objects/BucketDetails.vue';
const ActivateAccount = () => import('@/views/ActivateAccount.vue');
@ -114,7 +113,6 @@ export abstract class RouteConfig {
public static BucketsDetails = new NavigationLink('details', 'Bucket Details');
public static UploadFile = new NavigationLink('upload/', 'Objects Upload');
public static UploadFileChildren = new NavigationLink('*', 'Objects Upload Children');
public static BucketCreation = new NavigationLink('creation', 'Bucket Creation');
}
const isNewProjectDashboard = MetaUtils.getMetaContent('new-project-dashboard') === 'true';
@ -390,11 +388,6 @@ export const router = new Router({
},
],
},
{
path: RouteConfig.BucketCreation.path,
name: RouteConfig.BucketCreation.name,
component: BucketCreation,
},
],
},
],

View File

@ -102,9 +102,7 @@ export default store;
*/
router.beforeEach(async (to, from, next) => {
if (to.name === RouteConfig.NewProjectDashboard.name && from.name === RouteConfig.Login.name) {
if (store.state.appStateModule.isNewEncryptionPassphraseFlowEnabled) {
store.commit(APP_STATE_MUTATIONS.TOGGLE_HAS_JUST_LOGGED_IN);
}
store.commit(APP_STATE_MUTATIONS.TOGGLE_HAS_JUST_LOGGED_IN);
}
if (!to.path.includes(RouteConfig.UploadFile.path) && !store.state.appStateModule.appState.isUploadCancelPopupVisible) {

View File

@ -70,7 +70,6 @@ class State {
public couponCodeBillingUIEnabled = false,
public couponCodeSignupUIEnabled = false,
public isNewProjectDashboard = false,
public isNewEncryptionPassphraseFlowEnabled = false,
){}
}
@ -272,9 +271,6 @@ export const appStateModule = {
[APP_STATE_MUTATIONS.SET_PROJECT_DASHBOARD_STATUS](state: State, isNewProjectDashboard: boolean): void {
state.isNewProjectDashboard = isNewProjectDashboard;
},
[APP_STATE_MUTATIONS.SET_ENCRYPTION_PASSPHRASE_FLOW_STATUS](state: State, isNewEncryptionPassphraseFlowEnabled: boolean): void {
state.isNewEncryptionPassphraseFlowEnabled = isNewEncryptionPassphraseFlowEnabled;
},
[APP_STATE_MUTATIONS.SET_ONB_AG_NAME_STEP_BACK_ROUTE](state: State, backRoute: string): void {
state.appState.onbAGStepBackRoute = backRoute;
},
@ -442,9 +438,6 @@ export const appStateModule = {
[APP_STATE_ACTIONS.SET_PROJECT_DASHBOARD_STATUS]: function ({ commit }: AppContext, isNewProjectDashboard: boolean): void {
commit(APP_STATE_MUTATIONS.SET_PROJECT_DASHBOARD_STATUS, isNewProjectDashboard);
},
[APP_STATE_ACTIONS.SET_ENCRYPTION_PASSPHRASE_FLOW_STATUS]: function ({ commit }: AppContext, isNewEncryptionPassphraseFlowEnabled: boolean): void {
commit(APP_STATE_MUTATIONS.SET_ENCRYPTION_PASSPHRASE_FLOW_STATUS, isNewEncryptionPassphraseFlowEnabled);
},
[APP_STATE_ACTIONS.SET_COUPON_CODE_BILLING_UI_STATUS]: function ({ commit }: AppContext, couponCodeBillingUIEnabled: boolean): void {
commit(APP_STATE_MUTATIONS.SET_COUPON_CODE_BILLING_UI_STATUS, couponCodeBillingUIEnabled);
},

View File

@ -62,7 +62,6 @@ export const APP_STATE_MUTATIONS = {
SET_COUPON_CODE_BILLING_UI_STATUS: 'SET_COUPON_CODE_BILLING_UI_STATUS',
SET_COUPON_CODE_SIGNUP_UI_STATUS: 'SET_COUPON_CODE_SIGNUP_UI_STATUS',
SET_PROJECT_DASHBOARD_STATUS: 'SET_PROJECT_DASHBOARD_STATUS',
SET_ENCRYPTION_PASSPHRASE_FLOW_STATUS: 'SET_ENCRYPTION_PASSPHRASE_FLOW_STATUS',
SET_ONB_AG_NAME_STEP_BACK_ROUTE: 'SET_ONB_AG_NAME_STEP_BACK_ROUTE',
SET_ONB_API_KEY_STEP_BACK_ROUTE: 'SET_ONB_API_KEY_STEP_BACK_ROUTE',
SET_ONB_API_KEY: 'SET_ONB_API_KEY',

View File

@ -32,7 +32,6 @@ export const APP_STATE_ACTIONS = {
SET_COUPON_CODE_BILLING_UI_STATUS: 'SET_COUPON_CODE_BILLING_UI_STATUS',
SET_COUPON_CODE_SIGNUP_UI_STATUS: 'SET_COUPON_CODE_SIGNUP_UI_STATUS',
SET_PROJECT_DASHBOARD_STATUS: 'SET_PROJECT_DASHBOARD_STATUS',
SET_ENCRYPTION_PASSPHRASE_FLOW_STATUS: 'SET_ENCRYPTION_PASSPHRASE_FLOW_STATUS',
};
export const NOTIFICATION_ACTIONS = {