19 changed files with 1225 additions and 38 deletions
@ -0,0 +1,3 @@
@@ -0,0 +1,3 @@
|
||||
<form id="login-page" #form> |
||||
Login Form |
||||
</form> |
||||
@ -0,0 +1,44 @@
@@ -0,0 +1,44 @@
|
||||
import * as template from './login.component.html'; |
||||
|
||||
import { |
||||
Component, |
||||
ComponentFactoryResolver, |
||||
ViewChild, |
||||
ViewContainerRef, |
||||
} from '@angular/core'; |
||||
import { Router } from '@angular/router'; |
||||
|
||||
import { ToasterService } from 'angular2-toaster'; |
||||
import { Angulartics2 } from 'angulartics2'; |
||||
|
||||
import { AuthResult } from 'jslib/models/domain/authResult'; |
||||
|
||||
import { AuthService } from 'jslib/abstractions/auth.service'; |
||||
import { I18nService } from 'jslib/abstractions/i18n.service'; |
||||
import { SyncService } from 'jslib/abstractions/sync.service'; |
||||
|
||||
@Component({ |
||||
selector: 'app-login', |
||||
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) { } |
||||
|
||||
async submit() { |
||||
|
||||
} |
||||
|
||||
togglePassword() { |
||||
this.analytics.eventTrack.next({ action: 'Toggled Master Password on Login' }); |
||||
this.showPassword = !this.showPassword; |
||||
document.getElementById('masterPassword').focus(); |
||||
} |
||||
} |
||||
@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
|
||||
import { NgModule } from '@angular/core'; |
||||
import { |
||||
RouterModule, |
||||
Routes, |
||||
} from '@angular/router'; |
||||
|
||||
import { LoginComponent } from './accounts/login.component'; |
||||
|
||||
const routes: Routes = [ |
||||
{ path: '', redirectTo: '/login', pathMatch: 'full' }, |
||||
{ path: 'login', component: LoginComponent }, |
||||
]; |
||||
|
||||
@NgModule({ |
||||
imports: [RouterModule.forRoot(routes, { |
||||
useHash: true, |
||||
/*enableTracing: true,*/ |
||||
})], |
||||
exports: [RouterModule], |
||||
}) |
||||
export class AppRoutingModule { } |
||||
@ -0,0 +1,39 @@
@@ -0,0 +1,39 @@
|
||||
import { |
||||
ToasterConfig, |
||||
ToasterContainerComponent, |
||||
} from 'angular2-toaster'; |
||||
import { Angulartics2GoogleAnalytics } from 'angulartics2/ga'; |
||||
|
||||
import { |
||||
Component, |
||||
ComponentFactoryResolver, |
||||
NgZone, |
||||
OnDestroy, |
||||
OnInit, |
||||
Type, |
||||
ViewChild, |
||||
ViewContainerRef, |
||||
} from '@angular/core'; |
||||
import { Router } from '@angular/router'; |
||||
|
||||
import { ToasterService } from 'angular2-toaster'; |
||||
import { Angulartics2 } from 'angulartics2'; |
||||
|
||||
@Component({ |
||||
selector: 'app-root', |
||||
styles: [], |
||||
template: ` |
||||
<toaster-container [toasterconfig]="toasterConfig"></toaster-container> |
||||
<router-outlet></router-outlet>`, |
||||
}) |
||||
export class AppComponent { |
||||
toasterConfig: ToasterConfig = new ToasterConfig({ |
||||
showCloseButton: true, |
||||
mouseoverTimerStop: true, |
||||
animation: 'flyRight', |
||||
limit: 5, |
||||
}); |
||||
|
||||
constructor(private angulartics2GoogleAnalytics: Angulartics2GoogleAnalytics, private analytics: Angulartics2, |
||||
private toasterService: ToasterService) { } |
||||
} |
||||
@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
declare module '*.html'; |
||||
@ -0,0 +1,44 @@
@@ -0,0 +1,44 @@
|
||||
import 'core-js'; |
||||
import 'zone.js/dist/zone'; |
||||
|
||||
import { ToasterModule } from 'angular2-toaster'; |
||||
import { Angulartics2Module } from 'angulartics2'; |
||||
import { Angulartics2GoogleAnalytics } from 'angulartics2/ga'; |
||||
|
||||
import { AppRoutingModule } from './app-routing.module'; |
||||
import { ServicesModule } from './services/services.module'; |
||||
|
||||
import { NgModule } from '@angular/core'; |
||||
import { FormsModule } from '@angular/forms'; |
||||
import { BrowserModule } from '@angular/platform-browser'; |
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; |
||||
|
||||
import { AppComponent } from './app.component'; |
||||
|
||||
import { LoginComponent } from './accounts/login.component'; |
||||
|
||||
@NgModule({ |
||||
imports: [ |
||||
BrowserModule, |
||||
BrowserAnimationsModule, |
||||
FormsModule, |
||||
AppRoutingModule, |
||||
ServicesModule, |
||||
Angulartics2Module.forRoot([Angulartics2GoogleAnalytics], { |
||||
pageTracking: { |
||||
clearQueryParams: true, |
||||
}, |
||||
}), |
||||
ToasterModule, |
||||
], |
||||
declarations: [ |
||||
AppComponent, |
||||
LoginComponent, |
||||
], |
||||
entryComponents: [ |
||||
|
||||
], |
||||
providers: [], |
||||
bootstrap: [AppComponent], |
||||
}) |
||||
export class AppModule { } |
||||
@ -0,0 +1,14 @@
@@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html> |
||||
<html> |
||||
<head> |
||||
<meta charset="UTF-8"> |
||||
<meta name="viewport" content="width=device-width, initial-scale=1"> |
||||
<title>Bitwarden</title> |
||||
<base href=""> |
||||
</head> |
||||
<body> |
||||
<app-root> |
||||
<div id="loading"><i class="fa fa-spinner fa-spin fa-3x"></i></div> |
||||
</app-root> |
||||
</body> |
||||
</html> |
||||
@ -0,0 +1,15 @@
@@ -0,0 +1,15 @@
|
||||
import { enableProdMode } from '@angular/core'; |
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; |
||||
|
||||
// tslint:disable-next-line
|
||||
require('../scss/popup.scss'); |
||||
// tslint:disable-next-line
|
||||
require('../scripts/duo.js'); |
||||
|
||||
import { AppModule } from './app.module'; |
||||
|
||||
//if (!isDev()) {
|
||||
// enableProdMode();
|
||||
//}
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule); |
||||
@ -0,0 +1,31 @@
@@ -0,0 +1,31 @@
|
||||
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; |
||||
} |
||||
} |
||||
@ -0,0 +1,33 @@
@@ -0,0 +1,33 @@
|
||||
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); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,35 @@
@@ -0,0 +1,35 @@
|
||||
import { |
||||
APP_INITIALIZER, |
||||
NgModule, |
||||
} from '@angular/core'; |
||||
|
||||
import { ToasterModule } from 'angular2-toaster'; |
||||
|
||||
import { AuthGuardService } from './auth-guard.service'; |
||||
import { BroadcasterService } from './broadcaster.service'; |
||||
import { ValidationService } from './validation.service'; |
||||
|
||||
function initFactory(): Function { |
||||
return async () => { |
||||
|
||||
}; |
||||
} |
||||
|
||||
@NgModule({ |
||||
imports: [ |
||||
ToasterModule, |
||||
], |
||||
declarations: [], |
||||
providers: [ |
||||
ValidationService, |
||||
AuthGuardService, |
||||
{ |
||||
provide: APP_INITIALIZER, |
||||
useFactory: initFactory, |
||||
deps: [], |
||||
multi: true, |
||||
}, |
||||
], |
||||
}) |
||||
export class ServicesModule { |
||||
} |
||||
@ -0,0 +1,37 @@
@@ -0,0 +1,37 @@
|
||||
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; |
||||
} |
||||
} |
||||
@ -0,0 +1,150 @@
@@ -0,0 +1,150 @@
|
||||
const path = require('path'); |
||||
const webpack = require('webpack'); |
||||
const CleanWebpackPlugin = require('clean-webpack-plugin'); |
||||
const HtmlWebpackPlugin = require('html-webpack-plugin'); |
||||
const CopyWebpackPlugin = require('copy-webpack-plugin'); |
||||
const ExtractTextPlugin = require('extract-text-webpack-plugin'); |
||||
|
||||
const isVendorModule = (module) => { |
||||
if (!module.context) { |
||||
return false; |
||||
} |
||||
|
||||
const nodeModule = module.context.indexOf('node_modules') !== -1; |
||||
const bitwardenModule = module.context.indexOf('@bitwarden') !== -1; |
||||
return nodeModule && !bitwardenModule; |
||||
}; |
||||
|
||||
const extractCss = new ExtractTextPlugin({ |
||||
filename: '[name].css', |
||||
disable: false, |
||||
allChunks: true |
||||
}); |
||||
|
||||
module.exports = { |
||||
entry: { |
||||
'popup/main': './src/popup2/main.ts', |
||||
'background': './src/background.ts', |
||||
'content/autofill': './src/content/autofill.js', |
||||
'content/autofiller': './src/content/autofiller.js', |
||||
'content/notificationBar': './src/content/notificationBar.js', |
||||
'content/shortcuts': './src/content/shortcuts.js', |
||||
'downloader/downloader': './src/downloader/downloader.ts', |
||||
'2fa/2fa': './src/2fa/2fa.ts', |
||||
}, |
||||
module: { |
||||
rules: [ |
||||
{ |
||||
test: /\.ts$/, |
||||
enforce: 'pre', |
||||
loader: 'tslint-loader' |
||||
}, |
||||
{ |
||||
test: /\.tsx?$/, |
||||
use: 'ts-loader', |
||||
exclude: /node_modules\/(?!(@bitwarden)\/).*/ |
||||
}, |
||||
{ |
||||
test: /\.(html)$/, |
||||
loader: 'html-loader' |
||||
}, |
||||
{ |
||||
test: /.(ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/, |
||||
exclude: /loading.svg/, |
||||
use: [{ |
||||
loader: 'file-loader', |
||||
options: { |
||||
name: '[name].[ext]', |
||||
outputPath: 'popup/fonts/', |
||||
publicPath: './fonts/' |
||||
} |
||||
}] |
||||
}, |
||||
{ |
||||
test: /\.(jpe?g|png|gif|svg)$/i, |
||||
exclude: /.*(fontawesome-webfont|glyphicons-halflings-regular)\.svg/, |
||||
use: [{ |
||||
loader: 'file-loader', |
||||
options: { |
||||
name: '[name].[ext]', |
||||
outputPath: 'popup/images/', |
||||
publicPath: './images/' |
||||
} |
||||
}] |
||||
}, |
||||
{ |
||||
test: /\.scss$/, |
||||
use: extractCss.extract({ |
||||
use: [ |
||||
{ |
||||
loader: 'css-loader', |
||||
}, |
||||
{ |
||||
loader: 'sass-loader', |
||||
} |
||||
], |
||||
publicPath: '../' |
||||
}) |
||||
}, |
||||
] |
||||
}, |
||||
plugins: [ |
||||
new CleanWebpackPlugin([ |
||||
path.resolve(__dirname, 'build2/*') |
||||
]), |
||||
// ref: https://github.com/angular/angular/issues/20357
|
||||
new webpack.ContextReplacementPlugin( |
||||
/\@angular(\\|\/)core(\\|\/)esm5/, |
||||
path.resolve(__dirname, './src') |
||||
), |
||||
new webpack.optimize.CommonsChunkPlugin({ |
||||
name: 'popup/vendor', |
||||
chunks: ['popup/main'], |
||||
minChunks: isVendorModule |
||||
}), |
||||
new webpack.optimize.CommonsChunkPlugin({ |
||||
name: 'vendor', |
||||
chunks: ['background'], |
||||
minChunks: isVendorModule |
||||
}), |
||||
new HtmlWebpackPlugin({ |
||||
template: './src/popup2/index.html', |
||||
filename: 'popup/index.html', |
||||
chunks: ['popup/vendor', 'popup/main', 'fonts'] |
||||
}), |
||||
new HtmlWebpackPlugin({ |
||||
template: './src/background.html', |
||||
filename: 'background.html', |
||||
chunks: ['vendor', 'background'] |
||||
}), |
||||
new HtmlWebpackPlugin({ |
||||
template: './src/downloader/index.html', |
||||
filename: 'downloader/index.html', |
||||
chunks: ['downloader/downloader'] |
||||
}), |
||||
new HtmlWebpackPlugin({ |
||||
template: './src/2fa/index.html', |
||||
filename: '2fa/index.html', |
||||
chunks: ['2fa/2fa'] |
||||
}), |
||||
new CopyWebpackPlugin([ |
||||
'./src/manifest.json', |
||||
{ from: './src/_locales', to: '_locales' }, |
||||
{ from: './src/edge', to: 'edge' }, |
||||
{ from: './src/safari', to: 'safari' }, |
||||
{ from: './src/images', to: 'images' }, |
||||
{ from: './src/content/autofill.css', to: 'content' } |
||||
]), |
||||
extractCss |
||||
], |
||||
resolve: { |
||||
extensions: ['.tsx', '.ts', '.js'], |
||||
alias: { |
||||
jslib: path.join(__dirname, 'jslib/src') |
||||
} |
||||
}, |
||||
output: { |
||||
filename: '[name].js', |
||||
path: path.resolve(__dirname, 'build2') |
||||
} |
||||
}; |
||||
Loading…
Reference in new issue