mirror of
https://github.com/bitwarden/browser
synced 2025-12-13 06:43:35 +00:00
load service module
This commit is contained in:
2
jslib
2
jslib
Submodule jslib updated: 167558168c...579f970323
@@ -1,3 +1,43 @@
|
|||||||
<form id="login-page" #form>
|
<form id="login-page" #form (ngSubmit)="submit()" [appApiAction]="formPromise">
|
||||||
Login Form
|
<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> {{'settings' | i18n}}</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -22,18 +22,44 @@ import { SyncService } from 'jslib/abstractions/sync.service';
|
|||||||
template: template,
|
template: template,
|
||||||
})
|
})
|
||||||
export class LoginComponent {
|
export class LoginComponent {
|
||||||
@ViewChild('environment', { read: ViewContainerRef }) environmentModal: ViewContainerRef;
|
|
||||||
|
|
||||||
email: string = '';
|
email: string = '';
|
||||||
masterPassword: string = '';
|
masterPassword: string = '';
|
||||||
showPassword: boolean = false;
|
showPassword: boolean = false;
|
||||||
formPromise: Promise<AuthResult>;
|
formPromise: Promise<AuthResult>;
|
||||||
|
|
||||||
constructor(private router: Router, private analytics: Angulartics2,
|
constructor(private authService: AuthService, private router: Router,
|
||||||
private toasterService: ToasterService) { }
|
private analytics: Angulartics2, private toasterService: ToasterService,
|
||||||
|
private i18nService: I18nService, private syncService: SyncService) { }
|
||||||
|
|
||||||
async submit() {
|
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() {
|
togglePassword() {
|
||||||
|
|||||||
@@ -17,6 +17,15 @@ import { AppComponent } from './app.component';
|
|||||||
|
|
||||||
import { LoginComponent } from './accounts/login.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({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
@@ -32,8 +41,15 @@ import { LoginComponent } from './accounts/login.component';
|
|||||||
ToasterModule,
|
ToasterModule,
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
|
ApiActionDirective,
|
||||||
AppComponent,
|
AppComponent,
|
||||||
|
AutofocusDirective,
|
||||||
|
BlurClickDirective,
|
||||||
|
FallbackSrcDirective,
|
||||||
|
I18nPipe,
|
||||||
LoginComponent,
|
LoginComponent,
|
||||||
|
StopClickDirective,
|
||||||
|
StopPropDirective
|
||||||
],
|
],
|
||||||
entryComponents: [
|
entryComponents: [
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,13 +5,59 @@ import {
|
|||||||
|
|
||||||
import { ToasterModule } from 'angular2-toaster';
|
import { ToasterModule } from 'angular2-toaster';
|
||||||
|
|
||||||
import { AuthGuardService } from './auth-guard.service';
|
import { AuthGuardService } from 'jslib/angular/services/auth-guard.service';
|
||||||
import { BroadcasterService } from './broadcaster.service';
|
import { ValidationService } from 'jslib/angular/services/validation.service';
|
||||||
import { ValidationService } from './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 {
|
function initFactory(): Function {
|
||||||
return async () => {
|
return async () => {
|
||||||
|
if (getBgService<I18nService>('i18n2Service')() != null) {
|
||||||
|
authService.init();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,6 +69,36 @@ function initFactory(): Function {
|
|||||||
providers: [
|
providers: [
|
||||||
ValidationService,
|
ValidationService,
|
||||||
AuthGuardService,
|
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,
|
provide: APP_INITIALIZER,
|
||||||
useFactory: initFactory,
|
useFactory: initFactory,
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import AutofillPageDetails from '../../models/autofillPageDetails';
|
import AutofillPageDetails from '../../models/autofillPageDetails';
|
||||||
|
|
||||||
export interface AutofillService {
|
export abstract class AutofillService {
|
||||||
getFormsWithPasswordFields(pageDetails: AutofillPageDetails): any[];
|
getFormsWithPasswordFields: (pageDetails: AutofillPageDetails) => any[];
|
||||||
doAutoFill(options: any): Promise<string>;
|
doAutoFill: (options: any) => Promise<string>;
|
||||||
doAutoFillForLastUsedLogin(pageDetails: any, fromCommand: boolean): Promise<void>;
|
doAutoFillForLastUsedLogin: (pageDetails: any, fromCommand: boolean) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|||||||
10
webpack2.js
10
webpack2.js
@@ -135,13 +135,19 @@ module.exports = {
|
|||||||
{ from: './src/images', to: 'images' },
|
{ from: './src/images', to: 'images' },
|
||||||
{ from: './src/content/autofill.css', to: 'content' }
|
{ from: './src/content/autofill.css', to: 'content' }
|
||||||
]),
|
]),
|
||||||
|
new webpack.SourceMapDevToolPlugin({
|
||||||
|
filename: '[name].js.map',
|
||||||
|
include: ['popup/main.js']
|
||||||
|
}),
|
||||||
extractCss
|
extractCss
|
||||||
],
|
],
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: ['.tsx', '.ts', '.js'],
|
extensions: ['.tsx', '.ts', '.js'],
|
||||||
alias: {
|
alias: {
|
||||||
jslib: path.join(__dirname, 'jslib/src')
|
jslib: path.join(__dirname, 'jslib/src'),
|
||||||
}
|
},
|
||||||
|
symlinks: false,
|
||||||
|
modules: [path.resolve('node_modules')]
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
filename: '[name].js',
|
filename: '[name].js',
|
||||||
|
|||||||
Reference in New Issue
Block a user