load service module

This commit is contained in:
Kyle Spearrin 2018-04-04 08:27:31 -04:00
parent 4d56d12ccb
commit 5fd400bf9d
10 changed files with 182 additions and 119 deletions

2
jslib

@ -1 +1 @@
Subproject commit 167558168c4ddff8eff67d7f12dfac47d5d25866
Subproject commit 579f970323ea0bbc0d26f17cb9454c142f47bf6a

View File

@ -1,3 +1,43 @@
<form id="login-page" #form>
Login Form
<form id="login-page" #form (ngSubmit)="submit()" [appApiAction]="formPromise">
<div class="content">
<p class="lead">{{'loginOrCreateNewAccount' | i18n}}</p>
<div class="box last">
<div class="box-content">
<div class="box-content-row" appBoxRow>
<label for="email">{{'emailAddress' | i18n}}</label>
<input id="email" type="text" name="Email" [(ngModel)]="email" required
[appAutofocus]="email === ''">
</div>
<div class="box-content-row box-content-row-flex" appBoxRow>
<div class="row-main">
<label for="masterPassword">{{'masterPass' | i18n}}</label>
<input id="masterPassword" type="{{showPassword ? 'text' : 'password'}}" name="MasterPassword"
class="monospaced" [(ngModel)]="masterPassword" required [appAutofocus]="email !== ''">
</div>
<div class="action-buttons">
<a class="row-btn" href="#" appStopClick appBlurClick
title="{{'toggleVisibility' | i18n}}" (click)="togglePassword()">
<i class="fa fa-lg"
[ngClass]="{'fa-eye': !showPassword, 'fa-eye-slash': showPassword}"></i>
</a>
</div>
</div>
</div>
</div>
<div class="buttons">
<button type="submit" class="btn primary block" [disabled]="form.loading" appBlurClick>
<span [hidden]="form.loading"><i class="fa fa-sign-in"></i> {{'logIn' | i18n}}</span>
<i class="fa fa-spinner fa-spin" [hidden]="!form.loading"></i>
</button>
<a routerLink="/register" class="btn block">
<i class="fa fa-pencil-square-o"></i> {{'createAccount' | i18n}}
</a>
</div>
<div class="sub-options">
<a routerLink="/hint">{{'getMasterPasswordHint' | i18n}}</a>
</div>
<a href="#" appStopClick (click)="settings()" class="settings-icon">
<i class="fa fa-cog fa-lg"></i><span>&nbsp;{{'settings' | i18n}}</span>
</a>
</div>
</form>

View File

@ -22,18 +22,44 @@ import { SyncService } from 'jslib/abstractions/sync.service';
template: template,
})
export class LoginComponent {
@ViewChild('environment', { read: ViewContainerRef }) environmentModal: ViewContainerRef;
email: string = '';
masterPassword: string = '';
showPassword: boolean = false;
formPromise: Promise<AuthResult>;
constructor(private router: Router, private analytics: Angulartics2,
private toasterService: ToasterService) { }
constructor(private authService: AuthService, private router: Router,
private analytics: Angulartics2, private toasterService: ToasterService,
private i18nService: I18nService, private syncService: SyncService) { }
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;
}
try {
this.formPromise = this.authService.logIn(this.email, this.masterPassword);
const response = await this.formPromise;
if (response.twoFactor) {
this.analytics.eventTrack.next({ action: 'Logged In To Two-step' });
this.router.navigate(['2fa']);
} else {
this.syncService.fullSync(true);
this.analytics.eventTrack.next({ action: 'Logged In' });
this.router.navigate(['vault']);
}
} catch { }
}
togglePassword() {

View File

@ -17,6 +17,15 @@ import { AppComponent } from './app.component';
import { LoginComponent } from './accounts/login.component';
import { ApiActionDirective } from 'jslib/angular/directives/api-action.directive';
import { AutofocusDirective } from 'jslib/angular/directives/autofocus.directive';
import { BlurClickDirective } from 'jslib/angular/directives/blur-click.directive';
import { FallbackSrcDirective } from 'jslib/angular/directives/fallback-src.directive';
import { StopClickDirective } from 'jslib/angular/directives/stop-click.directive';
import { StopPropDirective } from 'jslib/angular/directives/stop-prop.directive';
import { I18nPipe } from 'jslib/angular/pipes/i18n.pipe';
@NgModule({
imports: [
BrowserModule,
@ -32,8 +41,15 @@ import { LoginComponent } from './accounts/login.component';
ToasterModule,
],
declarations: [
ApiActionDirective,
AppComponent,
AutofocusDirective,
BlurClickDirective,
FallbackSrcDirective,
I18nPipe,
LoginComponent,
StopClickDirective,
StopPropDirective
],
entryComponents: [

View File

@ -1,31 +0,0 @@
import { Injectable } from '@angular/core';
import {
CanActivate,
Router,
} from '@angular/router';
import { CryptoService } from 'jslib/abstractions/crypto.service';
import { MessagingService } from 'jslib/abstractions/messaging.service';
import { UserService } from 'jslib/abstractions/user.service';
@Injectable()
export class AuthGuardService implements CanActivate {
constructor(private cryptoService: CryptoService, private userService: UserService, private router: Router,
private messagingService: MessagingService) { }
async canActivate() {
const isAuthed = await this.userService.isAuthenticated();
if (!isAuthed) {
this.messagingService.send('logout');
return false;
}
const key = await this.cryptoService.getKey();
if (key == null) {
this.router.navigate(['lock']);
return false;
}
return true;
}
}

View File

@ -1,33 +0,0 @@
import { Injectable } from '@angular/core';
@Injectable()
export class BroadcasterService {
subscribers: Map<string, (message: any) => any> = new Map<string, (message: any) => any>();
send(message: any, id?: string) {
if (id != null) {
if (this.subscribers.has(id)) {
this.subscribers.get(id)(message);
}
return;
}
this.subscribers.forEach((value) => {
value(message);
});
}
subscribe(id: string, messageCallback: (message: any) => any) {
if (this.subscribers.has(id)) {
return;
}
this.subscribers.set(id, messageCallback);
}
unsubscribe(id: string) {
if (this.subscribers.has(id)) {
this.subscribers.delete(id);
}
}
}

View File

@ -5,13 +5,59 @@ import {
import { ToasterModule } from 'angular2-toaster';
import { AuthGuardService } from './auth-guard.service';
import { BroadcasterService } from './broadcaster.service';
import { ValidationService } from './validation.service';
import { AuthGuardService } from 'jslib/angular/services/auth-guard.service';
import { ValidationService } from 'jslib/angular/services/validation.service';
import { BrowserApi } from '../../browser/browserApi';
import { ApiService } from 'jslib/abstractions/api.service';
import { AppIdService } from 'jslib/abstractions/appId.service';
import { AuthService as AuthServiceAbstraction } from 'jslib/abstractions/auth.service';
import { AuditService } from 'jslib/abstractions/audit.service';
import { CipherService } from 'jslib/abstractions/cipher.service';
import { CollectionService } from 'jslib/abstractions/collection.service';
import { CryptoService } from 'jslib/abstractions/crypto.service';
import { EnvironmentService } from 'jslib/abstractions/environment.service';
import { FolderService } from 'jslib/abstractions/folder.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { LockService } from 'jslib/abstractions/lock.service';
import { MessagingService } from 'jslib/abstractions/messaging.service';
import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { SettingsService } from 'jslib/abstractions/settings.service';
import { StorageService } from 'jslib/abstractions/storage.service';
import { SyncService } from 'jslib/abstractions/sync.service';
import { TokenService } from 'jslib/abstractions/token.service';
import { TotpService } from 'jslib/abstractions/totp.service';
import { UserService } from 'jslib/abstractions/user.service';
import { UtilsService } from 'jslib/abstractions/utils.service';
import { AutofillService } from '../../services/abstractions/autofill.service';
import BrowserMessagingService from '../../services/browserMessaging.service';
import { AuthService } from 'jslib/services/auth.service';
import { ConstantsService } from 'jslib/services/constants.service';
function getBgService<T>(service: string) {
return (): T => {
const page = BrowserApi.getBackgroundPage();
return page ? page.bitwardenMain[service] as T : null;
};
}
const messagingService = new BrowserMessagingService(getBgService<PlatformUtilsService>('platformUtilsService')());
const authService = new AuthService(getBgService<CryptoService>('cryptoService')(),
getBgService<ApiService>('apiService')(), getBgService<UserService>('userService')(),
getBgService<TokenService>('tokenService')(), getBgService<AppIdService>('appIdService')(),
getBgService<I18nService>('i18n2Service')(), getBgService<PlatformUtilsService>('platformUtilsService')(),
getBgService<ConstantsService>('constantsService')(), messagingService);
function initFactory(): Function {
return async () => {
if (getBgService<I18nService>('i18n2Service')() != null) {
authService.init();
}
};
}
@ -23,6 +69,36 @@ function initFactory(): Function {
providers: [
ValidationService,
AuthGuardService,
{ provide: MessagingService, useValue: messagingService },
{ provide: AuthServiceAbstraction, useValue: authService },
{ provide: AuditService, useFactory: getBgService<AuditService>('auditService'), deps: [] },
{ provide: CipherService, useFactory: getBgService<CipherService>('cipherService'), deps: [] },
{ provide: FolderService, useFactory: getBgService<FolderService>('folderService'), deps: [] },
{ provide: CollectionService, useFactory: getBgService<CollectionService>('collectionService'), deps: [] },
{ provide: EnvironmentService, useFactory: getBgService<EnvironmentService>('environmentService'), deps: [] },
{ provide: TotpService, useFactory: getBgService<TotpService>('totpService'), deps: [] },
{ provide: TokenService, useFactory: getBgService<TokenService>('tokenService'), deps: [] },
{ provide: I18nService, useFactory: getBgService<I18nService>('i18n2Service'), deps: [] },
{ provide: UtilsService, useFactory: getBgService<UtilsService>('utilsService'), deps: [] },
{ provide: CryptoService, useFactory: getBgService<CryptoService>('cryptoService'), deps: [] },
{
provide: PlatformUtilsService,
useFactory: getBgService<PlatformUtilsService>('platformUtilsService'),
deps: []
},
{
provide: PasswordGenerationService,
useFactory: getBgService<PasswordGenerationService>('passwordGenerationService'),
deps: []
},
{ provide: ApiService, useFactory: getBgService<ApiService>('apiService'), deps: [] },
{ provide: SyncService, useFactory: getBgService<SyncService>('syncService'), deps: [] },
{ provide: UserService, useFactory: getBgService<UserService>('userService'), deps: [] },
{ provide: SettingsService, useFactory: getBgService<SettingsService>('settingsService'), deps: [] },
{ provide: LockService, useFactory: getBgService<LockService>('lockService'), deps: [] },
{ provide: StorageService, useFactory: getBgService<StorageService>('storageService'), deps: [] },
{ provide: AppIdService, useFactory: getBgService<AppIdService>('appIdService'), deps: [] },
{ provide: AutofillService, useFactory: getBgService<AutofillService>('autofillService'), deps: [] },
{
provide: APP_INITIALIZER,
useFactory: initFactory,

View File

@ -1,37 +0,0 @@
import { Injectable } from '@angular/core';
import { ToasterService } from 'angular2-toaster';
import { I18nService } from 'jslib/abstractions/i18n.service';
@Injectable()
export class ValidationService {
constructor(private toasterService: ToasterService, private i18nService: I18nService) { }
showError(data: any): string[] {
const defaultErrorMessage = this.i18nService.t('unexpectedError');
const errors: string[] = [];
if (data == null || typeof data !== 'object') {
errors.push(defaultErrorMessage);
} else if (data.validationErrors == null) {
errors.push(data.message ? data.message : defaultErrorMessage);
} else {
for (const key in data.validationErrors) {
if (!data.validationErrors.hasOwnProperty(key)) {
continue;
}
data.validationErrors[key].forEach((item: string) => {
errors.push(item);
});
}
}
if (errors.length > 0) {
this.toasterService.popAsync('error', this.i18nService.t('errorOccurred'), errors[0]);
}
return errors;
}
}

View File

@ -1,7 +1,7 @@
import AutofillPageDetails from '../../models/autofillPageDetails';
export interface AutofillService {
getFormsWithPasswordFields(pageDetails: AutofillPageDetails): any[];
doAutoFill(options: any): Promise<string>;
doAutoFillForLastUsedLogin(pageDetails: any, fromCommand: boolean): Promise<void>;
export abstract class AutofillService {
getFormsWithPasswordFields: (pageDetails: AutofillPageDetails) => any[];
doAutoFill: (options: any) => Promise<string>;
doAutoFillForLastUsedLogin: (pageDetails: any, fromCommand: boolean) => Promise<void>;
}

View File

@ -135,13 +135,19 @@ module.exports = {
{ from: './src/images', to: 'images' },
{ from: './src/content/autofill.css', to: 'content' }
]),
new webpack.SourceMapDevToolPlugin({
filename: '[name].js.map',
include: ['popup/main.js']
}),
extractCss
],
resolve: {
extensions: ['.tsx', '.ts', '.js'],
alias: {
jslib: path.join(__dirname, 'jslib/src')
}
jslib: path.join(__dirname, 'jslib/src'),
},
symlinks: false,
modules: [path.resolve('node_modules')]
},
output: {
filename: '[name].js',