-
-
{{'loginOrCreateNewAccount' | i18n}}
-
-
+
diff --git a/src/app/accounts/login.component.ts b/src/app/accounts/login.component.ts
index 4d697c06cc..1d57749a1d 100644
--- a/src/app/accounts/login.component.ts
+++ b/src/app/accounts/login.component.ts
@@ -24,7 +24,7 @@ export class LoginComponent {
constructor(private authService: AuthService, private router: Router, private analytics: Angulartics2,
private toasterService: ToasterService, private i18nService: I18nService) { }
- async onSubmit() {
+ async submit() {
if (this.email == null || this.email === '') {
this.toasterService.popAsync('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('emailRequired'));
diff --git a/src/app/accounts/register.component.html b/src/app/accounts/register.component.html
new file mode 100644
index 0000000000..7b84f34250
--- /dev/null
+++ b/src/app/accounts/register.component.html
@@ -0,0 +1,45 @@
+
diff --git a/src/app/accounts/register.component.ts b/src/app/accounts/register.component.ts
new file mode 100644
index 0000000000..1d79641065
--- /dev/null
+++ b/src/app/accounts/register.component.ts
@@ -0,0 +1,78 @@
+import * as template from './register.component.html';
+
+import {
+ Component,
+} from '@angular/core';
+
+import { Router } from '@angular/router';
+
+import { Angulartics2 } from 'angulartics2';
+import { ToasterService } from 'angular2-toaster';
+
+import { RegisterRequest } from 'jslib/models/request/registerRequest';
+
+import { ApiService } from 'jslib/abstractions/api.service';
+import { AuthService } from 'jslib/abstractions/auth.service';
+import { CryptoService } from 'jslib/abstractions/crypto.service';
+import { I18nService } from 'jslib/abstractions/i18n.service';
+
+@Component({
+ selector: 'app-register',
+ template: template,
+})
+export class RegisterComponent {
+ email: string = '';
+ masterPassword: string = '';
+ confirmMasterPassword: string = '';
+ hint: string = '';
+ formPromise: Promise
;
+
+ constructor(private authService: AuthService, private router: Router, private analytics: Angulartics2,
+ private toasterService: ToasterService, private i18nService: I18nService,
+ private cryptoService: CryptoService, private apiService: ApiService) { }
+
+ async submit() {
+ if (this.email == null || this.email === '') {
+ this.toasterService.popAsync('error', this.i18nService.t('errorOccurred'),
+ this.i18nService.t('emailRequired'));
+ return;
+ }
+ if (this.email.indexOf('@') === -1) {
+ this.toasterService.popAsync('error', this.i18nService.t('errorOccurred'),
+ this.i18nService.t('invalidEmail'));
+ return;
+ }
+ if (this.masterPassword == null || this.masterPassword === '') {
+ this.toasterService.popAsync('error', this.i18nService.t('errorOccurred'),
+ this.i18nService.t('masterPassRequired'));
+ return;
+ }
+ if (this.masterPassword.length < 8) {
+ this.toasterService.popAsync('error', this.i18nService.t('errorOccurred'),
+ this.i18nService.t('masterPassLength'));
+ return;
+ }
+ if (this.masterPassword !== this.confirmMasterPassword) {
+ this.toasterService.popAsync('error', this.i18nService.t('errorOccurred'),
+ this.i18nService.t('masterPassDoesntMatch'));
+ return;
+ }
+
+ try {
+ this.formPromise = this.register();
+ await this.formPromise;
+ this.analytics.eventTrack.next({ action: 'Registered' });
+ this.toasterService.popAsync('success', null, this.i18nService.t('newAccountCreated'));
+ this.router.navigate(['login']);
+ } catch { }
+ }
+
+ private async register() {
+ this.email = this.email.toLowerCase();
+ const key = this.cryptoService.makeKey(this.masterPassword, this.email);
+ const encKey = await this.cryptoService.makeEncKey(key);
+ const hashedPassword = await this.cryptoService.hashPassword(this.masterPassword, key);
+ const request = new RegisterRequest(this.email, hashedPassword, this.hint, encKey.encryptedString);
+ await this.apiService.postRegister(request);
+ }
+}
diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts
index fc858be02e..25bb879908 100644
--- a/src/app/app-routing.module.ts
+++ b/src/app/app-routing.module.ts
@@ -5,11 +5,13 @@ import {
} from '@angular/router';
import { LoginComponent } from './accounts/login.component';
+import { RegisterComponent } from './accounts/register.component';
import { VaultComponent } from './vault/vault.component';
const routes: Routes = [
{ path: '', redirectTo: '/login', pathMatch: 'full' },
{ path: 'login', component: LoginComponent },
+ { path: 'register', component: RegisterComponent },
{ path: 'vault', component: VaultComponent },
];
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 8c42e6187e..11f8bcc1fe 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -26,6 +26,7 @@ import { IconComponent } from './vault/icon.component';
import { LoginComponent } from './accounts/login.component';
import { ModalComponent } from './modal.component';
import { PasswordGeneratorComponent } from './vault/password-generator.component';
+import { RegisterComponent } from './accounts/register.component';
import { SearchCiphersPipe } from './pipes/search-ciphers.pipe';
import { StopClickDirective } from './directives/stop-click.directive';
import { StopPropDirective } from './directives/stop-prop.directive';
@@ -62,6 +63,7 @@ import { ViewComponent } from './vault/view.component';
LoginComponent,
ModalComponent,
PasswordGeneratorComponent,
+ RegisterComponent,
SearchCiphersPipe,
StopClickDirective,
StopPropDirective,
diff --git a/src/app/services/services.module.ts b/src/app/services/services.module.ts
index a35233134d..b591d5e113 100644
--- a/src/app/services/services.module.ts
+++ b/src/app/services/services.module.ts
@@ -130,7 +130,7 @@ function initFactory(i18n: I18nService, platformUtilsService: DesktopPlatformUti
{ provide: CryptoServiceAbstraction, useValue: cryptoService },
{ provide: PlatformUtilsServiceAbstraction, useValue: platformUtilsService },
{ provide: PasswordGenerationServiceAbstraction, useValue: passwordGenerationService },
- { provide: PasswordGenerationServiceAbstraction, useValue: passwordGenerationService },
+ { provide: ApiServiceAbstraction, useValue: apiService },
{
provide: APP_INITIALIZER,
useFactory: initFactory,
diff --git a/src/scss/buttons.scss b/src/scss/buttons.scss
index 51353290ff..8ef719f6ef 100644
--- a/src/scss/buttons.scss
+++ b/src/scss/buttons.scss
@@ -7,6 +7,8 @@
border: 1px solid $button-border-color;
font-size: $font-size-base;
color: $button-color;
+ white-space: nowrap;
+ text-align: center;
&:hover:not([disabled]), &:focus:not([disabled]) {
cursor: pointer;
diff --git a/src/scss/pages.scss b/src/scss/pages.scss
index ee8a89c5f6..8b44428dac 100644
--- a/src/scss/pages.scss
+++ b/src/scss/pages.scss
@@ -31,9 +31,17 @@
margin-bottom: 20px;
}
+ .box {
+ margin-bottom: 20px;
+
+ &.last {
+ margin-bottom: 15px;
+ }
+ }
+
.buttons {
display: flex;
- margin: 15px 0 20px;
+ margin-bottom: 20px;
button {
margin-right: 10px;