mirror of
https://github.com/bitwarden/desktop.git
synced 2024-11-16 10:35:31 +01:00
Merge pull request #367 from bitwarden/typescript
Typescript conversion
This commit is contained in:
commit
22409461dc
16
.editorconfig
Normal file
16
.editorconfig
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# EditorConfig is awesome: http://EditorConfig.org
|
||||||
|
|
||||||
|
# top-most EditorConfig file
|
||||||
|
root = true
|
||||||
|
|
||||||
|
# Unix-style newlines with a newline ending every file
|
||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
# Matches multiple files with brace expansion notation
|
||||||
|
# Set default charset
|
||||||
|
[*.{js,ts,less}]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -9,3 +9,5 @@ webfonts/
|
|||||||
*.crx
|
*.crx
|
||||||
*.pem
|
*.pem
|
||||||
*.zip
|
*.zip
|
||||||
|
releases/
|
||||||
|
package-lock.json
|
||||||
|
22
README.md
22
README.md
@ -27,19 +27,31 @@ The bitwarden browser extension is written using the Chrome Web Extension API an
|
|||||||
By default the extension is targeting the production API. If you are running the [Core](https://github.com/bitwarden/core) API locally, you'll need to switch the extension to target your local instance. Open `src/services/apiService.js` and set `self.baseUrl` and `self.identityBaseUrl` to your local API instance (ex. `http://localhost:5000`).
|
By default the extension is targeting the production API. If you are running the [Core](https://github.com/bitwarden/core) API locally, you'll need to switch the extension to target your local instance. Open `src/services/apiService.js` and set `self.baseUrl` and `self.identityBaseUrl` to your local API instance (ex. `http://localhost:5000`).
|
||||||
|
|
||||||
Then run the following commands:
|
Then run the following commands:
|
||||||
|
```bash
|
||||||
- `npm install`
|
npm install
|
||||||
- `gulp build`
|
npm run dev:watch
|
||||||
|
```
|
||||||
|
|
||||||
You can now load the extension into your browser through the browser's extension tools page:
|
You can now load the extension into your browser through the browser's extension tools page:
|
||||||
|
|
||||||
- Chrome/Opera:
|
- Chrome/Opera:
|
||||||
1. Type `chrome://extensions` in your address bar to bring up the extensions page.
|
1. Type `chrome://extensions` in your address bar to bring up the extensions page.
|
||||||
2. Enable developer mode (checkbox)
|
2. Enable developer mode (checkbox)
|
||||||
3. Click the "Load unpacked extension" button, navigate to the `src` folder of your local extension instance, and click "Ok".
|
3. Click the "Load unpacked extension" button, navigate to the `dist` folder of your local extension instance, and click "Ok".
|
||||||
- Firefox
|
- Firefox
|
||||||
1. Type `about:debugging` in your address bar to bring up the add-ons page.
|
1. Type `about:debugging` in your address bar to bring up the add-ons page.
|
||||||
2. Click the `Load Temporary Add-on` button, navigate to the `src/manifest.json` file, and "Open".
|
2. Click the `Load Temporary Add-on` button, navigate to the `dist/manifest.json` file, and "Open".
|
||||||
|
|
||||||
|
### Release
|
||||||
|
|
||||||
|
To build the the extension for production the following commands should be run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run prod
|
||||||
|
gulp dist:[browser]
|
||||||
|
```
|
||||||
|
|
||||||
|
Where `[browser]` is the web browser to target. Currently the following web browsers are supported: `chrome`, `edge`, `firefox` and `opera`.
|
||||||
|
|
||||||
# Contribute
|
# Contribute
|
||||||
|
|
||||||
|
604
gulpfile.js
604
gulpfile.js
@ -1,504 +1,122 @@
|
|||||||
var gulp = require('gulp'),
|
const gulp = require('gulp'),
|
||||||
rimraf = require('rimraf'),
|
gulpif = require('gulp-if'),
|
||||||
concat = require('gulp-concat'),
|
filter = require('gulp-filter'),
|
||||||
rename = require('gulp-rename'),
|
replace = require('gulp-replace'),
|
||||||
less = require('gulp-less'),
|
|
||||||
preprocess = require('gulp-preprocess'),
|
|
||||||
runSequence = require('run-sequence'),
|
|
||||||
jshint = require('gulp-jshint'),
|
jshint = require('gulp-jshint'),
|
||||||
merge = require('merge-stream'),
|
|
||||||
browserify = require('browserify'),
|
|
||||||
source = require('vinyl-source-stream'),
|
|
||||||
googleWebFonts = require('gulp-google-webfonts'),
|
googleWebFonts = require('gulp-google-webfonts'),
|
||||||
webpack = require('webpack-stream'),
|
|
||||||
jeditor = require("gulp-json-editor"),
|
jeditor = require("gulp-json-editor"),
|
||||||
gulpUtil = require('gulp-util'),
|
|
||||||
child = require('child_process'),
|
child = require('child_process'),
|
||||||
zip = require('gulp-zip'),
|
zip = require('gulp-zip'),
|
||||||
manifest = require('./src/manifest.json'),
|
manifest = require('./src/manifest.json'),
|
||||||
xmlpoke = require('gulp-xmlpoke'),
|
xmlpoke = require('gulp-xmlpoke');
|
||||||
embedTemplates = require('gulp-angular-embed-templates');
|
|
||||||
|
|
||||||
var paths = {};
|
const paths = {
|
||||||
paths.dist = './dist/';
|
releases: './releases/',
|
||||||
paths.libDir = './src/lib/';
|
dist: './dist/',
|
||||||
paths.npmDir = './node_modules/';
|
libDir: './src/lib/',
|
||||||
paths.popupDir = './src/popup/';
|
npmDir: './node_modules/',
|
||||||
paths.lessDir = paths.popupDir + 'less/';
|
popupDir: './src/popup/',
|
||||||
paths.cssDir = paths.popupDir + 'css/';
|
cssDir: './src/popup/css/'
|
||||||
|
};
|
||||||
|
|
||||||
gulp.task('lint', function () {
|
const sidebarActionManifestObj = {
|
||||||
return gulp.src([
|
|
||||||
paths.popupDir + '**/*.js',
|
|
||||||
'./src/services/**/*.js',
|
|
||||||
'./src/notification/**/*.js',
|
|
||||||
'./src/models/**/*.js',
|
|
||||||
'./src/scripts/**/*.js',
|
|
||||||
//'./src/content/**/*.js',
|
|
||||||
'./src/overlay/**/*.js',
|
|
||||||
'./src/background.js'
|
|
||||||
])
|
|
||||||
.pipe(jshint())
|
|
||||||
.pipe(jshint.reporter('default'));
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('build', function (cb) {
|
|
||||||
return runSequence(
|
|
||||||
'clean',
|
|
||||||
['browserify', 'webpack', 'lib', 'less', 'lint', 'webfonts'],
|
|
||||||
cb);
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('clean:css', function (cb) {
|
|
||||||
return rimraf(paths.cssDir, cb);
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('clean:lib', function (cb) {
|
|
||||||
return rimraf(paths.libDir, cb);
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('clean', ['clean:css', 'clean:lib']);
|
|
||||||
|
|
||||||
gulp.task('lib', ['clean:lib'], function () {
|
|
||||||
var libs = [
|
|
||||||
{
|
|
||||||
src: [
|
|
||||||
paths.npmDir + 'bootstrap/dist/**/*',
|
|
||||||
'!' + paths.npmDir + 'bootstrap/dist/**/npm.js',
|
|
||||||
'!' + paths.npmDir + 'bootstrap/dist/**/css/*theme*',
|
|
||||||
'!' + paths.npmDir + 'bootstrap/**/*.min*'
|
|
||||||
],
|
|
||||||
dest: paths.libDir + 'bootstrap'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: paths.npmDir + 'font-awesome/css/font-awesome.css',
|
|
||||||
dest: paths.libDir + 'font-awesome/css'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: paths.npmDir + 'font-awesome/fonts/*',
|
|
||||||
dest: paths.libDir + 'font-awesome/fonts'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: paths.npmDir + 'jquery/dist/jquery.js',
|
|
||||||
dest: paths.libDir + 'jquery'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: paths.npmDir + 'angular/angular.js',
|
|
||||||
dest: paths.libDir + 'angular'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: paths.npmDir + 'angular-animate/angular-animate.js',
|
|
||||||
dest: paths.libDir + 'angular-animate'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: paths.npmDir + 'angular-ui-router/release/angular-ui-router.js',
|
|
||||||
dest: paths.libDir + 'angular-ui-router'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: [paths.npmDir + 'angular-toastr/dist/angular-toastr.tpls.js',
|
|
||||||
paths.npmDir + 'angular-toastr/dist/angular-toastr.css'],
|
|
||||||
dest: paths.libDir + 'angular-toastr'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: paths.npmDir + 'ngclipboard/dist/ngclipboard.js',
|
|
||||||
dest: paths.libDir + 'ngclipboard'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: paths.npmDir + 'clipboard/dist/clipboard.js',
|
|
||||||
dest: paths.libDir + 'clipboard'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: paths.npmDir + 'q/q.js',
|
|
||||||
dest: paths.libDir + 'q'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: [paths.npmDir + 'sweetalert/dist/sweetalert.css', paths.npmDir + 'sweetalert/dist/sweetalert-dev.js',
|
|
||||||
paths.npmDir + 'angular-sweetalert/SweetAlert.js'],
|
|
||||||
dest: paths.libDir + 'sweetalert'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: [paths.npmDir + 'angulartics-google-analytics/lib/angulartics*.js',
|
|
||||||
paths.npmDir + 'angulartics/src/angulartics.js'
|
|
||||||
],
|
|
||||||
dest: paths.libDir + 'angulartics'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: paths.npmDir + 'ng-infinite-scroll/build/ng-infinite-scroll.js',
|
|
||||||
dest: paths.libDir + 'ng-infinite-scroll'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: paths.npmDir + 'papaparse/papaparse.js',
|
|
||||||
dest: paths.libDir + 'papaparse'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
var tasks = libs.map(function (lib) {
|
|
||||||
return gulp.src(lib.src).pipe(gulp.dest(lib.dest));
|
|
||||||
});
|
|
||||||
|
|
||||||
return merge(tasks);
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('browserify', ['browserify:tldjs']);
|
|
||||||
|
|
||||||
gulp.task('browserify:tldjs', function () {
|
|
||||||
return browserify(paths.npmDir + 'tldjs/index.js', { standalone: 'tldjs' })
|
|
||||||
.bundle()
|
|
||||||
.pipe(source('tld.js'))
|
|
||||||
.pipe(gulp.dest(paths.libDir + 'tldjs'));
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('webpack', ['webpack:forge']);
|
|
||||||
|
|
||||||
gulp.task('webpack:forge', function () {
|
|
||||||
var forgeDir = paths.npmDir + '/node-forge/lib/';
|
|
||||||
|
|
||||||
return gulp.src([
|
|
||||||
forgeDir + 'pbkdf2.js',
|
|
||||||
forgeDir + 'aes.js',
|
|
||||||
forgeDir + 'hmac.js',
|
|
||||||
forgeDir + 'sha256.js',
|
|
||||||
forgeDir + 'random.js',
|
|
||||||
forgeDir + 'forge.js'
|
|
||||||
]).pipe(webpack({
|
|
||||||
output: {
|
|
||||||
filename: 'forge.js',
|
|
||||||
library: 'forge',
|
|
||||||
libraryTarget: 'umd'
|
|
||||||
},
|
|
||||||
node: {
|
|
||||||
Buffer: false,
|
|
||||||
process: false,
|
|
||||||
crypto: false,
|
|
||||||
setImmediate: false
|
|
||||||
}
|
|
||||||
})).pipe(gulp.dest(paths.libDir + 'forge'));
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('less', function () {
|
|
||||||
return gulp.src(paths.lessDir + 'popup.less')
|
|
||||||
.pipe(less())
|
|
||||||
.pipe(gulp.dest(paths.cssDir));
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('watch', function () {
|
|
||||||
gulp.watch(paths.lessDir + '*.less', ['less']);
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('dist:clean', function (cb) {
|
|
||||||
return rimraf(paths.dist + '**/*', cb);
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('dist:move', function () {
|
|
||||||
var moves = [
|
|
||||||
{
|
|
||||||
src: 'src/_locales/**/*',
|
|
||||||
dest: paths.dist + '_locales'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: [
|
|
||||||
'src/content/**/*',
|
|
||||||
'!src/content/field.js',
|
|
||||||
'!src/content/overlay.js'
|
|
||||||
],
|
|
||||||
dest: paths.dist + 'content'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: 'src/images/**/*',
|
|
||||||
dest: paths.dist + 'images'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: 'src/notification/**/*',
|
|
||||||
dest: paths.dist + 'notification'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: 'src/popup/index.html',
|
|
||||||
dest: paths.dist + 'popup'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: 'src/popup/css/webfonts/**/*',
|
|
||||||
dest: paths.dist + 'popup/css/webfonts'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: paths.libDir + 'font-awesome/fonts/**/*',
|
|
||||||
dest: paths.dist + 'popup/fonts'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: 'src/services/**/*',
|
|
||||||
dest: paths.dist + 'services'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: paths.libDir + 'forge/**/*',
|
|
||||||
dest: paths.dist + 'lib/forge'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: paths.libDir + 'jquery/**/*',
|
|
||||||
dest: paths.dist + 'lib/jquery'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: paths.libDir + 'tldjs/**/*',
|
|
||||||
dest: paths.dist + 'lib/tldjs'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: paths.libDir + 'q/**/*',
|
|
||||||
dest: paths.dist + 'lib/q'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: 'src/models/**/*',
|
|
||||||
dest: paths.dist + 'models'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: 'src/scripts/analytics.js',
|
|
||||||
dest: paths.dist + 'scripts'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: [
|
|
||||||
'src/background.*',
|
|
||||||
'src/manifest.json'
|
|
||||||
],
|
|
||||||
dest: paths.dist
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
var tasks = moves.map(function (move) {
|
|
||||||
return gulp.src(move.src).pipe(gulp.dest(move.dest));
|
|
||||||
});
|
|
||||||
|
|
||||||
return merge(tasks);
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('dist:css', function () {
|
|
||||||
distCss({});
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('dist:css:edge', function () {
|
|
||||||
distCss({ edge: true });
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('dist:css:firefox', function () {
|
|
||||||
distCss({ firefox: true });
|
|
||||||
});
|
|
||||||
|
|
||||||
function distCss(preprocessContext) {
|
|
||||||
return gulp
|
|
||||||
.src([
|
|
||||||
// libs
|
|
||||||
paths.libDir + '**/*.css',
|
|
||||||
'!' + paths.libDir + '**/*.min.css',
|
|
||||||
// app
|
|
||||||
paths.cssDir + 'popup.css',
|
|
||||||
paths.cssDir + 'webfonts.css'
|
|
||||||
])
|
|
||||||
.pipe(preprocess({ context: preprocessContext }))
|
|
||||||
.pipe(concat(paths.dist + 'popup/css/popup.css'))
|
|
||||||
.pipe(gulp.dest('.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
gulp.task('dist:js', function () {
|
|
||||||
return distJs(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('dist:js:edge', function () {
|
|
||||||
return distJs(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
function distJs(edge) {
|
|
||||||
var appTask = gulp
|
|
||||||
.src([
|
|
||||||
// models/scripts
|
|
||||||
'./src/models/**/*.js',
|
|
||||||
'./src/scripts/*.js',
|
|
||||||
// app
|
|
||||||
paths.popupDir + 'app/app.js',
|
|
||||||
paths.popupDir + 'app/**/*Module.js',
|
|
||||||
paths.popupDir + 'app/**/*.js'
|
|
||||||
])
|
|
||||||
.pipe(embedTemplates({
|
|
||||||
basePath: './src/popup/',
|
|
||||||
minimize: { empty: true }
|
|
||||||
}))
|
|
||||||
.pipe(concat(paths.dist + 'popup/app.js'))
|
|
||||||
.pipe(gulp.dest('.'));
|
|
||||||
|
|
||||||
var libTask = gulp
|
|
||||||
.src([
|
|
||||||
paths.libDir + 'jquery/jquery.js',
|
|
||||||
paths.libDir + 'bootstrap/js/bootstrap.js',
|
|
||||||
edge ? './src/edge/angular.js' : (paths.libDir + 'angular/angular.js'),
|
|
||||||
paths.libDir + '**/*.js',
|
|
||||||
'!' + paths.libDir + 'q/**/*',
|
|
||||||
'!' + paths.libDir + 'tldjs/**/*',
|
|
||||||
'!' + paths.libDir + 'forge/**/*',
|
|
||||||
'!' + paths.libDir + '**/*.min.js'
|
|
||||||
])
|
|
||||||
.pipe(concat(paths.dist + 'popup/lib.js'))
|
|
||||||
.pipe(gulp.dest('.'));
|
|
||||||
|
|
||||||
return merge(appTask, libTask);
|
|
||||||
}
|
|
||||||
|
|
||||||
gulp.task('dist:preprocess', function () {
|
|
||||||
return gulp
|
|
||||||
.src([
|
|
||||||
paths.dist + 'popup/index.html'
|
|
||||||
], { base: '.' })
|
|
||||||
.pipe(preprocess({ context: {} }))
|
|
||||||
.pipe(gulp.dest('.'));
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('dist', ['build'], function (cb) {
|
|
||||||
return dist({}, cb);
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('dist:edge', ['build'], function (cb) {
|
|
||||||
return dist({ edge: true }, cb);
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('dist:firefox', ['build'], function (cb) {
|
|
||||||
return dist({ firefox: true }, cb);
|
|
||||||
});
|
|
||||||
|
|
||||||
function dist(o, cb) {
|
|
||||||
var distCss = o.edge ? 'dist:css:edge' : o.firefox ? 'dist:css:firefox' : 'dist:css';
|
|
||||||
var distJs = o.edge ? 'dist:js:edge' : 'dist:js';
|
|
||||||
|
|
||||||
return runSequence(
|
|
||||||
'dist:clean',
|
|
||||||
['dist:move', distCss, distJs],
|
|
||||||
'dist:preprocess',
|
|
||||||
cb);
|
|
||||||
}
|
|
||||||
|
|
||||||
var sidebarActionManifestObj = {
|
|
||||||
"default_title": "bitwarden",
|
"default_title": "bitwarden",
|
||||||
"default_panel": "popup/index.html?uilocation=sidebar",
|
"default_panel": "popup/index.html?uilocation=sidebar",
|
||||||
"default_icon": "images/icon19.png"
|
"default_icon": "images/icon19.png"
|
||||||
};
|
};
|
||||||
|
|
||||||
gulp.task('dist-firefox', ['dist:firefox'], function (cb) {
|
function dist(browserName, manifest) {
|
||||||
gulp.src(paths.dist + 'manifest.json')
|
return gulp.src(paths.dist + '**/*')
|
||||||
.pipe(jeditor(function (manifest) {
|
.pipe(gulpif(browserName !== 'edge', filter(['**', '!dist/edge/**/*'])))
|
||||||
manifest.applications = {
|
.pipe(gulpif('popup/index.html', replace('__BROWSER__', browserName)))
|
||||||
gecko: {
|
.pipe(gulpif('manifest.json', jeditor(manifest)))
|
||||||
id: '{446900e4-71c2-419f-a6a7-df9c091e268b}',
|
.pipe(zip(`dist-${browserName}.zip`))
|
||||||
strict_min_version: '42.0'
|
.pipe(gulp.dest(paths.releases));
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
manifest['sidebar_action'] = sidebarActionManifestObj;
|
gulp.task('dist', ['dist:firefox', 'dist:chrome', 'dist:opera', 'dist:edge']);
|
||||||
return manifest;
|
|
||||||
}))
|
|
||||||
.pipe(gulp.dest(paths.dist));
|
|
||||||
return zipDist('dist-firefox');
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('dist-opera', ['dist'], function (cb) {
|
gulp.task('dist:firefox', (cb) => {
|
||||||
gulp.src(paths.dist + 'manifest.json')
|
return dist('firefox', (manifest) => {
|
||||||
.pipe(jeditor(function (manifest) {
|
manifest.applications = {
|
||||||
manifest['sidebar_action'] = sidebarActionManifestObj;
|
gecko: {
|
||||||
return manifest;
|
id: '{446900e4-71c2-419f-a6a7-df9c091e268b}',
|
||||||
}))
|
strict_min_version: '42.0'
|
||||||
.pipe(gulp.dest(paths.dist));
|
}
|
||||||
return zipDist('dist-opera');
|
};
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('dist-edge', ['dist:edge'], function (cb) {
|
manifest['sidebar_action'] = sidebarActionManifestObj;
|
||||||
// move dist to temp extension folder
|
return manifest;
|
||||||
new Promise(function (resolve, reject) {
|
|
||||||
gulp.src(paths.dist + '**/*')
|
|
||||||
.on('error', reject)
|
|
||||||
.pipe(gulp.dest('temp/Extension/'))
|
|
||||||
.on('end', resolve);
|
|
||||||
}).then(function () {
|
|
||||||
// move windows store files to temp folder
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
gulp.src('store/windows/**/*')
|
|
||||||
.on('error', reject)
|
|
||||||
.pipe(gulp.dest('temp/'))
|
|
||||||
.on('end', resolve);
|
|
||||||
});
|
|
||||||
}).then(function () {
|
|
||||||
// delete dist folder
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
rimraf(paths.dist, function () {
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}).then(function () {
|
|
||||||
// move temp back to dist
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
gulp.src('temp/**/*')
|
|
||||||
.on('error', reject)
|
|
||||||
.pipe(gulp.dest(paths.dist))
|
|
||||||
.on('end', resolve);
|
|
||||||
});
|
|
||||||
}).then(function () {
|
|
||||||
// delete temp folder
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
rimraf('temp', function () {
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}).then(function () {
|
|
||||||
// move src edge folder to dist
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
gulp.src(['src/edge/**/*', '!src/edge/angular.js'])
|
|
||||||
.on('error', reject)
|
|
||||||
.pipe(gulp.dest(paths.dist + 'Extension/edge'))
|
|
||||||
.on('end', resolve);
|
|
||||||
});
|
|
||||||
}).then(function () {
|
|
||||||
// modify manifest with edge preload stuff
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
gulp.src(paths.dist + 'Extension/manifest.json')
|
|
||||||
.pipe(jeditor(function (manifest) {
|
|
||||||
manifest['-ms-preload'] = {
|
|
||||||
backgroundScript: 'edge/backgroundScriptsAPIBridge.js',
|
|
||||||
contentScript: 'edge/contentScriptsAPIBridge.js'
|
|
||||||
};
|
|
||||||
return manifest;
|
|
||||||
}))
|
|
||||||
.on('error', reject)
|
|
||||||
.pipe(gulp.dest(paths.dist + 'Extension'))
|
|
||||||
.on('end', resolve);
|
|
||||||
});
|
|
||||||
}).then(function () {
|
|
||||||
// modify appxmanifest
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
gulp.src(paths.dist + '/AppxManifest.xml')
|
|
||||||
.pipe(xmlpoke({
|
|
||||||
replacements: [{
|
|
||||||
xpath: '/p:Package/p:Identity/@Version',
|
|
||||||
value: manifest.version + '.0',
|
|
||||||
namespaces: {
|
|
||||||
'p': 'http://schemas.microsoft.com/appx/manifest/foundation/windows10'
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}))
|
|
||||||
.on('error', reject)
|
|
||||||
.pipe(gulp.dest(paths.dist))
|
|
||||||
.on('end', resolve);
|
|
||||||
});
|
|
||||||
}).then(function () {
|
|
||||||
// makeappx.exe must be in your system's path already
|
|
||||||
child.spawn('makeappx.exe', ['pack', '/h', 'SHA256', '/d', paths.dist, '/p', paths.dist + 'bitwarden.appx']);
|
|
||||||
cb();
|
|
||||||
}, function () {
|
|
||||||
cb();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('dist-other', ['dist'], function (cb) {
|
gulp.task('dist:opera', (cb) => {
|
||||||
return zipDist('dist-other');
|
return dist('opera', (manifest) => {
|
||||||
|
manifest['sidebar_action'] = sidebarActionManifestObj;
|
||||||
|
return manifest;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function zipDist(fileName) {
|
gulp.task('dist:chrome', (cb) => {
|
||||||
return gulp.src(paths.dist + '**/*')
|
return dist('chrome', (manifest) => {
|
||||||
.pipe(zip(fileName + '.zip'))
|
return manifest;
|
||||||
.pipe(gulp.dest(paths.dist));
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Since Edge extensions require makeappx to be run we temporarily store it in a folder.
|
||||||
|
gulp.task('dist:edge', (cb) => {
|
||||||
|
const edgePath = paths.releases + 'Edge/';
|
||||||
|
const extensionPath = edgePath + 'Extension/';
|
||||||
|
|
||||||
|
return copyDistEdge(paths.dist + '**/*', extensionPath)
|
||||||
|
.then(copyAssetsEdge('./store/windows/**/*', edgePath))
|
||||||
|
.then(() => {
|
||||||
|
// makeappx.exe must be in your system's path already
|
||||||
|
child.spawn('makeappx.exe', ['pack', '/h', 'SHA256', '/d', edgePath, '/p', paths.releases + 'dist-edge.appx']);
|
||||||
|
return cb;
|
||||||
|
}, () => {
|
||||||
|
return cb;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function copyDistEdge(source, dest) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
gulp.src(source)
|
||||||
|
.on('error', reject)
|
||||||
|
.pipe(gulpif('popup/index.html', replace('__BROWSER__', 'edge')))
|
||||||
|
.pipe(gulpif('manifest.json', jeditor((manifest) => {
|
||||||
|
manifest['-ms-preload'] = {
|
||||||
|
backgroundScript: 'edge/backgroundScriptsAPIBridge.js',
|
||||||
|
contentScript: 'edge/contentScriptsAPIBridge.js'
|
||||||
|
};
|
||||||
|
return manifest;
|
||||||
|
})))
|
||||||
|
.pipe(gulp.dest(dest))
|
||||||
|
.on('end', resolve);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
gulp.task('webfonts', function () {
|
function copyAssetsEdge(source, dest) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
gulp.src(source)
|
||||||
|
.on('error', reject)
|
||||||
|
.pipe(gulpif('AppxManifest.xml', xmlpoke({
|
||||||
|
replacements: [{
|
||||||
|
xpath: '/p:Package/p:Identity/@Version',
|
||||||
|
value: manifest.version + '.0',
|
||||||
|
namespaces: {
|
||||||
|
'p': 'http://schemas.microsoft.com/appx/manifest/foundation/windows10'
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
})))
|
||||||
|
.pipe(gulp.dest(dest))
|
||||||
|
.on('end', resolve);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
gulp.task('build', ['lint', 'webfonts']);
|
||||||
|
|
||||||
|
gulp.task('webfonts', () => {
|
||||||
return gulp.src('./webfonts.list')
|
return gulp.src('./webfonts.list')
|
||||||
.pipe(googleWebFonts({
|
.pipe(googleWebFonts({
|
||||||
fontsDir: 'webfonts',
|
fontsDir: 'webfonts',
|
||||||
@ -507,20 +125,20 @@ gulp.task('webfonts', function () {
|
|||||||
.pipe(gulp.dest(paths.cssDir));
|
.pipe(gulp.dest(paths.cssDir));
|
||||||
});
|
});
|
||||||
|
|
||||||
function npmCommand(commands, cb) {
|
// LEGACY CODE!
|
||||||
var npmLogger = (buffer) => {
|
|
||||||
buffer.toString()
|
|
||||||
.split(/\n/)
|
|
||||||
.forEach((message) => gulpUtil.log(message));
|
|
||||||
};
|
|
||||||
var npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
||||||
var npmChild = child.spawn(npmCommand, commands);
|
|
||||||
npmChild.stdout.on('data', npmLogger);
|
|
||||||
npmChild.stderr.on('data', npmLogger);
|
|
||||||
npmChild.stderr.on('close', cb);
|
|
||||||
return npmChild;
|
|
||||||
}
|
|
||||||
|
|
||||||
gulp.task('webext:firefox', function (cb) {
|
gulp.task('lint', () => {
|
||||||
return npmCommand(['run', 'start:firefox'], cb);
|
return gulp.src([
|
||||||
|
paths.popupDir + '**/*.js',
|
||||||
|
'./src/services/**/*.js',
|
||||||
|
'./src/notification/**/*.js',
|
||||||
|
'./src/scripts/**/*.js',
|
||||||
|
//'./src/content/**/*.js',
|
||||||
|
'./src/overlay/**/*.js',
|
||||||
|
'./src/background.js'
|
||||||
|
])
|
||||||
|
.pipe(jshint({
|
||||||
|
esversion: 6
|
||||||
|
}))
|
||||||
|
.pipe(jshint.reporter('default'));
|
||||||
});
|
});
|
||||||
|
49
package.json
49
package.json
@ -2,47 +2,66 @@
|
|||||||
"name": "bitwarden",
|
"name": "bitwarden",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start:firefox": "web-ext run --source-dir ./dist/"
|
"start:firefox": "web-ext run --source-dir ./dist/",
|
||||||
|
"dev": "gulp build && webpack --config webpack.dev.js",
|
||||||
|
"dev:watch": "gulp build && webpack --config webpack.dev.js --watch",
|
||||||
|
"prod": "gulp build && webpack --config webpack.prod.js",
|
||||||
|
"lint": "tslint src/**/*.ts || true",
|
||||||
|
"lint:fix": "tslint src/**/*.ts --fix"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"angular": "1.6.6",
|
"angular": "1.6.6",
|
||||||
"angular-animate": "1.6.6",
|
"angular-animate": "1.6.6",
|
||||||
"angular-sweetalert": "1.1.2",
|
"angular-sweetalert": "1.1.2",
|
||||||
"angular-toastr": "2.1.1",
|
"angular-toastr": "2.1.1",
|
||||||
"angular-ui-router": "0.4.2",
|
|
||||||
"angulartics": "1.4.0",
|
"angulartics": "1.4.0",
|
||||||
"angulartics-google-analytics": "0.4.0",
|
"angulartics-google-analytics": "0.4.0",
|
||||||
"bootstrap": "3.3.7",
|
"bootstrap": "3.3.7",
|
||||||
"browserify": "14.4.0",
|
|
||||||
"child_process": "1.0.2",
|
"child_process": "1.0.2",
|
||||||
|
"clean-webpack-plugin": "^0.1.17",
|
||||||
"clipboard": "1.7.1",
|
"clipboard": "1.7.1",
|
||||||
|
"copy-webpack-plugin": "^4.2.0",
|
||||||
|
"css-loader": "^0.28.7",
|
||||||
|
"extract-text-webpack-plugin": "^3.0.1",
|
||||||
|
"file-loader": "^1.1.5",
|
||||||
"font-awesome": "4.7.0",
|
"font-awesome": "4.7.0",
|
||||||
"gulp": "3.9.1",
|
"gulp": "3.9.1",
|
||||||
"gulp-angular-embed-templates": "2.3.0",
|
"gulp-filter": "5.0.1",
|
||||||
"gulp-concat": "2.6.1",
|
|
||||||
"gulp-google-webfonts": "0.0.14",
|
"gulp-google-webfonts": "0.0.14",
|
||||||
|
"gulp-if": "^2.0.2",
|
||||||
"gulp-jshint": "2.0.4",
|
"gulp-jshint": "2.0.4",
|
||||||
"gulp-json-editor": "2.2.1",
|
"gulp-json-editor": "2.2.1",
|
||||||
"gulp-less": "3.3.2",
|
"gulp-replace": "^0.6.1",
|
||||||
"gulp-preprocess": "2.0.0",
|
|
||||||
"gulp-rename": "1.2.2",
|
|
||||||
"gulp-util": "3.0.8",
|
|
||||||
"gulp-xmlpoke": "0.2.1",
|
"gulp-xmlpoke": "0.2.1",
|
||||||
"gulp-zip": "4.0.0",
|
"gulp-zip": "4.0.0",
|
||||||
|
"html-loader": "^0.5.1",
|
||||||
|
"html-webpack-plugin": "^2.30.1",
|
||||||
"jquery": "3.2.1",
|
"jquery": "3.2.1",
|
||||||
"jshint": "2.9.5",
|
"jshint": "2.9.5",
|
||||||
"merge-stream": "1.0.1",
|
"less": "^3.0.0-alpha.3",
|
||||||
|
"less-loader": "^4.0.5",
|
||||||
"ng-infinite-scroll": "1.3.0",
|
"ng-infinite-scroll": "1.3.0",
|
||||||
"ngclipboard": "1.1.1",
|
"ngclipboard": "1.1.1",
|
||||||
"node-forge": "0.7.1",
|
"node-forge": "0.7.1",
|
||||||
"papaparse": "4.3.5",
|
"papaparse": "4.3.5",
|
||||||
"q": "1.5.0",
|
"style-loader": "^0.19.0",
|
||||||
"rimraf": "2.6.1",
|
|
||||||
"run-sequence": "2.1.0",
|
|
||||||
"sweetalert": "1.1.3",
|
"sweetalert": "1.1.3",
|
||||||
"tldjs": "2.0.0",
|
"tldjs": "2.0.0",
|
||||||
"vinyl-source-stream": "1.1.0",
|
"ts-loader": "^3.0.5",
|
||||||
|
"tslint": "^5.8.0",
|
||||||
|
"tslint-loader": "^3.5.3",
|
||||||
|
"typescript": "^2.5.3",
|
||||||
"web-ext": "2.0.0",
|
"web-ext": "2.0.0",
|
||||||
"webpack-stream": "4.0.0"
|
"webpack": "^3.8.1",
|
||||||
|
"webpack-merge": "^4.1.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@types/angular": "^1.6.34",
|
||||||
|
"@types/chrome": "0.0.51",
|
||||||
|
"@types/jquery": "^3.2.16",
|
||||||
|
"@types/node-forge": "0.6.10",
|
||||||
|
"@types/tldjs": "1.7.1",
|
||||||
|
"@types/webcrypto": "^0.0.28",
|
||||||
|
"@uirouter/angularjs": "^1.0.10"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
5
src/background.d.ts
vendored
Normal file
5
src/background.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
declare function escape(s: string): string;
|
||||||
|
declare function unescape(s: string): string;
|
||||||
|
declare var opr: any;
|
||||||
|
declare var tldjs: any;
|
||||||
|
declare var forge: any;
|
@ -1,33 +1,6 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<script type="text/javascript" src="lib/jquery/jquery.js"></script>
|
|
||||||
<script type="text/javascript" src="lib/q/q.js"></script>
|
|
||||||
<script type="text/javascript" src="lib/tldjs/tld.js"></script>
|
|
||||||
<script type="text/javascript" src="lib/forge/forge.js"></script>
|
|
||||||
<script type="text/javascript" src="models/api/requestModels.js"></script>
|
|
||||||
<script type="text/javascript" src="models/api/responseModels.js"></script>
|
|
||||||
<script type="text/javascript" src="models/dataModels.js"></script>
|
|
||||||
<script type="text/javascript" src="models/domainModels.js"></script>
|
|
||||||
<script type="text/javascript" src="services/i18nService.js"></script>
|
|
||||||
<script type="text/javascript" src="services/constantsService.js"></script>
|
|
||||||
<script type="text/javascript" src="services/utilsService.js"></script>
|
|
||||||
<script type="text/javascript" src="services/cryptoService.js"></script>
|
|
||||||
<script type="text/javascript" src="services/tokenService.js"></script>
|
|
||||||
<script type="text/javascript" src="services/apiService.js"></script>
|
|
||||||
<script type="text/javascript" src="services/userService.js"></script>
|
|
||||||
<script type="text/javascript" src="services/settingsService.js"></script>
|
|
||||||
<script type="text/javascript" src="services/folderService.js"></script>
|
|
||||||
<script type="text/javascript" src="services/cipherService.js"></script>
|
|
||||||
<script type="text/javascript" src="services/lockService.js"></script>
|
|
||||||
<script type="text/javascript" src="services/syncService.js"></script>
|
|
||||||
<script type="text/javascript" src="services/autofillService.js"></script>
|
|
||||||
<script type="text/javascript" src="services/appIdService.js"></script>
|
|
||||||
<script type="text/javascript" src="services/passwordGenerationService.js"></script>
|
|
||||||
<script type="text/javascript" src="services/totpService.js"></script>
|
|
||||||
<script type="text/javascript" src="services/environmentService.js"></script>
|
|
||||||
<script type="text/javascript" src="background.js"></script>
|
|
||||||
<script type="text/javascript" src="scripts/analytics.js"></script>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,3 +1,69 @@
|
|||||||
|
window.forge = require('node-forge');
|
||||||
|
window.tldjs = require('tldjs');
|
||||||
|
|
||||||
|
// Service imports
|
||||||
|
import ApiService from './services/api.service';
|
||||||
|
import AppIdService from './services/appId.service';
|
||||||
|
import AutofillService from './services/autofill.service';
|
||||||
|
import CipherService from './services/cipher.service';
|
||||||
|
import ConstantsService from './services/constants.service';
|
||||||
|
import CryptoService from './services/crypto.service';
|
||||||
|
import EnvironmentService from './services/environment.service';
|
||||||
|
import FolderService from './services/folder.service';
|
||||||
|
import i18nService from './services/i18nService.js';
|
||||||
|
import LockService from './services/lock.service';
|
||||||
|
import PasswordGenerationService from './services/passwordGeneration.service';
|
||||||
|
import SettingsService from './services/settings.service';
|
||||||
|
import SyncService from './services/sync.service';
|
||||||
|
import TokenService from './services/token.service';
|
||||||
|
import TotpService from './services/totp.service';
|
||||||
|
import UserService from './services/user.service';
|
||||||
|
import UtilsService from './services/utils.service';
|
||||||
|
|
||||||
|
// Model imports
|
||||||
|
import { Attachment } from './models/domain/attachment';
|
||||||
|
import { Card } from './models/domain/card';
|
||||||
|
import { Cipher } from './models/domain/cipher';
|
||||||
|
import { Field } from './models/domain/field';
|
||||||
|
import { Folder } from './models/domain/folder';
|
||||||
|
import { Identity } from './models/domain/identity';
|
||||||
|
import { Login } from './models/domain/login';
|
||||||
|
import { SecureNote } from './models/domain/secureNote';
|
||||||
|
|
||||||
|
import { AttachmentData } from './models/data/attachmentData';
|
||||||
|
import { CardData } from './models/data/cardData';
|
||||||
|
import { CipherData } from './models/data/cipherData';
|
||||||
|
import { FieldData } from './models/data/fieldData';
|
||||||
|
import { FolderData } from './models/data/folderData';
|
||||||
|
import { IdentityData } from './models/data/identityData';
|
||||||
|
import { LoginData } from './models/data/loginData';
|
||||||
|
import { SecureNoteData } from './models/data/secureNoteData';
|
||||||
|
|
||||||
|
import { CipherString } from './models/domain/cipherString';
|
||||||
|
|
||||||
|
import { CipherRequest } from './models/request/cipherRequest';
|
||||||
|
import { DeviceRequest } from './models/request/deviceRequest';
|
||||||
|
import { DeviceTokenRequest } from './models/request/deviceTokenRequest';
|
||||||
|
import { FolderRequest } from './models/request/folderRequest';
|
||||||
|
import { PasswordHintRequest } from './models/request/passwordHintRequest';
|
||||||
|
import { RegisterRequest } from './models/request/registerRequest';
|
||||||
|
import { TokenRequest } from './models/request/tokenRequest';
|
||||||
|
import { TwoFactorEmailRequest } from './models/request/twoFactorEmailRequest';
|
||||||
|
|
||||||
|
import { AttachmentResponse } from './models/response/attachmentResponse';
|
||||||
|
import { CipherResponse } from './models/response/cipherResponse';
|
||||||
|
import { DeviceResponse } from './models/response/deviceResponse';
|
||||||
|
import { DomainsResponse } from './models/response/domainsResponse';
|
||||||
|
import { ErrorResponse } from './models/response/errorResponse';
|
||||||
|
import { FolderResponse } from './models/response/folderResponse';
|
||||||
|
import { GlobalDomainResponse } from './models/response/globalDomainResponse';
|
||||||
|
import { IdentityTokenResponse } from './models/response/identityTokenResponse';
|
||||||
|
import { KeysResponse } from './models/response/keysResponse';
|
||||||
|
import { ListResponse } from './models/response/listResponse';
|
||||||
|
import { ProfileOrganizationResponse } from './models/response/profileOrganizationResponse';
|
||||||
|
import { ProfileResponse } from './models/response/profileResponse';
|
||||||
|
import { SyncResponse } from './models/response/syncResponse';
|
||||||
|
|
||||||
var bg_isBackground = true,
|
var bg_isBackground = true,
|
||||||
bg_utilsService,
|
bg_utilsService,
|
||||||
bg_i18nService,
|
bg_i18nService,
|
||||||
@ -28,27 +94,25 @@ var bg_isBackground = true,
|
|||||||
bg_sidebarAction = (typeof opr !== 'undefined') && opr.sidebarAction ? opr.sidebarAction : chrome.sidebarAction;
|
bg_sidebarAction = (typeof opr !== 'undefined') && opr.sidebarAction ? opr.sidebarAction : chrome.sidebarAction;
|
||||||
|
|
||||||
// init services
|
// init services
|
||||||
bg_utilsService = new UtilsService();
|
window.bg_utilsService = bg_utilsService = new UtilsService();
|
||||||
bg_i18nService = new i18nService(bg_utilsService);
|
window.bg_i18nService = bg_i18nService = new i18nService(bg_utilsService);
|
||||||
bg_constantsService = new ConstantsService(bg_i18nService);
|
window.bg_constantsService = bg_constantsService = new ConstantsService(bg_i18nService);
|
||||||
bg_cryptoService = new CryptoService(bg_constantsService, bg_utilsService);
|
window.bg_cryptoService = bg_cryptoService = new CryptoService();
|
||||||
bg_tokenService = new TokenService(bg_utilsService);
|
window.bg_tokenService = bg_tokenService = new TokenService();
|
||||||
bg_appIdService = new AppIdService(bg_utilsService);
|
window.bg_appIdService = bg_appIdService = new AppIdService();
|
||||||
bg_apiService = new ApiService(bg_tokenService, bg_appIdService, bg_utilsService, bg_constantsService, logout);
|
window.bg_apiService = bg_apiService = new ApiService(bg_tokenService, logout);
|
||||||
bg_environmentService = new EnvironmentService(bg_constantsService, bg_apiService);
|
window.bg_environmentService = bg_environmentService = new EnvironmentService(bg_apiService);
|
||||||
bg_userService = new UserService(bg_tokenService, bg_apiService, bg_cryptoService, bg_utilsService);
|
window.bg_userService = bg_userService = new UserService(bg_tokenService);
|
||||||
bg_settingsService = new SettingsService(bg_userService, bg_utilsService);
|
window.bg_settingsService = bg_settingsService = new SettingsService(bg_userService);
|
||||||
bg_cipherService = new CipherService(bg_cryptoService, bg_userService, bg_apiService, bg_settingsService, bg_utilsService,
|
window.bg_cipherService = bg_cipherService = new CipherService(bg_cryptoService, bg_userService, bg_settingsService, bg_apiService);
|
||||||
bg_constantsService);
|
window.bg_folderService = bg_folderService = new FolderService(bg_cryptoService, bg_userService, bg_i18nService, bg_apiService);
|
||||||
bg_folderService = new FolderService(bg_cryptoService, bg_userService, bg_apiService, bg_i18nService, bg_utilsService);
|
window.bg_lockService = bg_lockService = new LockService(bg_cipherService, bg_folderService, bg_cryptoService, bg_utilsService, setIcon, refreshBadgeAndMenu);
|
||||||
bg_lockService = new LockService(bg_constantsService, bg_cryptoService, bg_folderService, bg_cipherService, bg_utilsService,
|
window.bg_syncService = bg_syncService = new SyncService(bg_userService, bg_apiService, bg_settingsService, bg_folderService, bg_cipherService, bg_cryptoService, logout);
|
||||||
setIcon, refreshBadgeAndMenu);
|
window.bg_passwordGenerationService = bg_passwordGenerationService = new PasswordGenerationService(bg_cryptoService);
|
||||||
bg_syncService = new SyncService(bg_cipherService, bg_folderService, bg_userService, bg_apiService, bg_settingsService,
|
window.bg_totpService = bg_totpService = new TotpService();
|
||||||
bg_cryptoService, logout);
|
window.bg_autofillService = bg_autofillService = new AutofillService(bg_cipherService, bg_tokenService, bg_totpService, bg_utilsService);
|
||||||
bg_passwordGenerationService = new PasswordGenerationService(bg_constantsService, bg_utilsService, bg_cryptoService);
|
|
||||||
bg_totpService = new TotpService(bg_constantsService);
|
require('./scripts/analytics.js');
|
||||||
bg_autofillService = new AutofillService(bg_utilsService, bg_totpService, bg_tokenService, bg_cipherService,
|
|
||||||
bg_constantsService);
|
|
||||||
|
|
||||||
if (chrome.commands) {
|
if (chrome.commands) {
|
||||||
chrome.commands.onCommand.addListener(function (command) {
|
chrome.commands.onCommand.addListener(function (command) {
|
||||||
@ -58,7 +122,7 @@ var bg_isBackground = true,
|
|||||||
eventAction: 'Generated Password From Command'
|
eventAction: 'Generated Password From Command'
|
||||||
});
|
});
|
||||||
bg_passwordGenerationService.getOptions().then(function (options) {
|
bg_passwordGenerationService.getOptions().then(function (options) {
|
||||||
var password = bg_passwordGenerationService.generatePassword(options);
|
var password = PasswordGenerationService.generatePassword(options);
|
||||||
bg_utilsService.copyToClipboard(password);
|
bg_utilsService.copyToClipboard(password);
|
||||||
bg_passwordGenerationService.addHistory(password);
|
bg_passwordGenerationService.addHistory(password);
|
||||||
});
|
});
|
||||||
@ -193,7 +257,7 @@ var bg_isBackground = true,
|
|||||||
eventAction: 'Generated Password From Context Menu'
|
eventAction: 'Generated Password From Context Menu'
|
||||||
});
|
});
|
||||||
bg_passwordGenerationService.getOptions().then(function (options) {
|
bg_passwordGenerationService.getOptions().then(function (options) {
|
||||||
var password = bg_passwordGenerationService.generatePassword(options);
|
var password = PasswordGenerationService.generatePassword(options);
|
||||||
bg_utilsService.copyToClipboard(password);
|
bg_utilsService.copyToClipboard(password);
|
||||||
bg_passwordGenerationService.addHistory(password);
|
bg_passwordGenerationService.addHistory(password);
|
||||||
});
|
});
|
||||||
@ -384,19 +448,21 @@ var bg_isBackground = true,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bg_userService.isAuthenticated(function (isAuthenticated) {
|
var isAuthenticated;
|
||||||
bg_cryptoService.getKey().then(function (key) {
|
bg_userService.isAuthenticated().then(function (theIsAuthenticated) {
|
||||||
var suffix = '';
|
isAuthenticated = theIsAuthenticated;
|
||||||
if (!isAuthenticated) {
|
return bg_cryptoService.getKey();
|
||||||
suffix = '_gray';
|
}).then(function (key) {
|
||||||
}
|
var suffix = '';
|
||||||
else if (!key) {
|
if (!isAuthenticated) {
|
||||||
suffix = '_locked';
|
suffix = '_gray';
|
||||||
}
|
}
|
||||||
|
else if (!key) {
|
||||||
|
suffix = '_locked';
|
||||||
|
}
|
||||||
|
|
||||||
actionSetIcon(chrome.browserAction, suffix);
|
actionSetIcon(chrome.browserAction, suffix);
|
||||||
actionSetIcon(bg_sidebarAction, suffix);
|
actionSetIcon(bg_sidebarAction, suffix);
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function actionSetIcon(theAction, suffix) {
|
function actionSetIcon(theAction, suffix) {
|
||||||
@ -845,24 +911,25 @@ var bg_isBackground = true,
|
|||||||
}
|
}
|
||||||
|
|
||||||
function logout(expired, callback) {
|
function logout(expired, callback) {
|
||||||
bg_syncService.setLastSync(new Date(0), function () {
|
bg_userService.getUserId().then(function (userId) {
|
||||||
bg_userService.getUserIdPromise().then(function (userId) {
|
return Promise.all([
|
||||||
return Q.all([
|
bg_syncService.setLastSync(new Date(0)),
|
||||||
bg_tokenService.clearToken(),
|
bg_tokenService.clearToken(),
|
||||||
bg_cryptoService.clearKeys(),
|
bg_cryptoService.clearKeys(),
|
||||||
bg_userService.clear(),
|
bg_userService.clear(),
|
||||||
bg_settingsService.clear(userId),
|
bg_settingsService.clear(userId),
|
||||||
bg_cipherService.clear(userId),
|
bg_cipherService.clear(userId),
|
||||||
bg_folderService.clear(userId),
|
bg_folderService.clear(userId),
|
||||||
bg_passwordGenerationService.clear()
|
bg_passwordGenerationService.clear()
|
||||||
]).then(function () {
|
]).then(function () {
|
||||||
chrome.runtime.sendMessage({
|
chrome.runtime.sendMessage({
|
||||||
command: 'doneLoggingOut', expired: expired
|
command: 'doneLoggingOut', expired: expired
|
||||||
});
|
|
||||||
setIcon();
|
|
||||||
refreshBadgeAndMenu();
|
|
||||||
callback();
|
|
||||||
});
|
});
|
||||||
|
setIcon();
|
||||||
|
refreshBadgeAndMenu();
|
||||||
|
if (callback) {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -873,7 +940,7 @@ var bg_isBackground = true,
|
|||||||
var syncInternal = 6 * 60 * 60 * 1000; // 6 hours
|
var syncInternal = 6 * 60 * 60 * 1000; // 6 hours
|
||||||
var lastSyncAgo = new Date() - lastSync;
|
var lastSyncAgo = new Date() - lastSync;
|
||||||
if (override || !lastSync || lastSyncAgo >= syncInternal) {
|
if (override || !lastSync || lastSyncAgo >= syncInternal) {
|
||||||
bg_syncService.fullSync(override || false, function () {
|
bg_syncService.fullSync(override || false).then(function () {
|
||||||
scheduleNextSync();
|
scheduleNextSync();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -893,7 +960,7 @@ var bg_isBackground = true,
|
|||||||
|
|
||||||
// Bootstrap
|
// Bootstrap
|
||||||
|
|
||||||
bg_environmentService.setUrlsFromStorage(function () {
|
bg_environmentService.setUrlsFromStorage().then(function () {
|
||||||
setIcon();
|
setIcon();
|
||||||
cleanupbg_loginsToAdd();
|
cleanupbg_loginsToAdd();
|
||||||
fullSync(true);
|
fullSync(true);
|
||||||
|
32
src/content/autofill.css
Normal file
32
src/content/autofill.css
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
@-webkit-keyframes onepasswordfill {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: scale(1.0,1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
-webkit-transform: scale(1.2,1.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: scale(1.0,1.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@-moz-keyframes onepasswordfill {
|
||||||
|
0% {
|
||||||
|
transform: scale(1.0,1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
transform: scale(1.2,1.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: scale(1.0,1.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.com-agilebits-onepassword-extension-animated-fill {
|
||||||
|
animation: onepasswordfill 200ms ease-in-out 0ms 1;
|
||||||
|
-webkit-animation: onepasswordfill 200ms ease-in-out 0ms 1;
|
||||||
|
}
|
33901
src/edge/angular.js
vendored
33901
src/edge/angular.js
vendored
File diff suppressed because it is too large
Load Diff
6
src/enums/browserType.enum.ts
Normal file
6
src/enums/browserType.enum.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export enum BrowserType {
|
||||||
|
Chrome = 2,
|
||||||
|
Firefox = 3,
|
||||||
|
Opera = 4,
|
||||||
|
Edge = 5,
|
||||||
|
}
|
6
src/enums/cipherType.enum.ts
Normal file
6
src/enums/cipherType.enum.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export enum CipherType {
|
||||||
|
Login = 1,
|
||||||
|
SecureNote = 2,
|
||||||
|
Card = 3,
|
||||||
|
Identity = 4,
|
||||||
|
}
|
9
src/enums/encryptionType.enum.ts
Normal file
9
src/enums/encryptionType.enum.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export enum EncryptionType {
|
||||||
|
AesCbc256_B64 = 0,
|
||||||
|
AesCbc128_HmacSha256_B64 = 1,
|
||||||
|
AesCbc256_HmacSha256_B64 = 2,
|
||||||
|
Rsa2048_OaepSha256_B64 = 3,
|
||||||
|
Rsa2048_OaepSha1_B64 = 4,
|
||||||
|
Rsa2048_OaepSha256_HmacSha256_B64 = 5,
|
||||||
|
Rsa2048_OaepSha1_HmacSha256_B64 = 6,
|
||||||
|
}
|
5
src/enums/fieldType.enum.ts
Normal file
5
src/enums/fieldType.enum.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export enum FieldType {
|
||||||
|
Text = 0,
|
||||||
|
Hidden = 1,
|
||||||
|
Boolean = 2,
|
||||||
|
}
|
3
src/enums/secureNoteType.enum.ts
Normal file
3
src/enums/secureNoteType.enum.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export enum SecureNoteType {
|
||||||
|
Generic = 0,
|
||||||
|
}
|
@ -50,6 +50,18 @@
|
|||||||
"file:///*"
|
"file:///*"
|
||||||
],
|
],
|
||||||
"run_at": "document_start"
|
"run_at": "document_start"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"all_frames": true,
|
||||||
|
"css": [
|
||||||
|
"content/autofill.css"
|
||||||
|
],
|
||||||
|
"matches": [
|
||||||
|
"http://*/*",
|
||||||
|
"https://*/*",
|
||||||
|
"file:///*"
|
||||||
|
],
|
||||||
|
"run_at": "document_end"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"background": {
|
"background": {
|
||||||
@ -100,4 +112,4 @@
|
|||||||
"overlay/popup.html",
|
"overlay/popup.html",
|
||||||
"notification/bar.html"
|
"notification/bar.html"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -1,139 +0,0 @@
|
|||||||
var CipherRequest = function (cipher) {
|
|
||||||
this.type = cipher.type;
|
|
||||||
this.folderId = cipher.folderId;
|
|
||||||
this.organizationId = cipher.organizationId;
|
|
||||||
this.name = cipher.name ? cipher.name.encryptedString : null;
|
|
||||||
this.notes = cipher.notes ? cipher.notes.encryptedString : null;
|
|
||||||
this.favorite = cipher.favorite;
|
|
||||||
|
|
||||||
var constantsService = chrome.extension.getBackgroundPage().bg_constantsService;
|
|
||||||
switch (this.type) {
|
|
||||||
case constantsService.cipherType.login:
|
|
||||||
this.login = {
|
|
||||||
uri: cipher.login.uri ? cipher.login.uri.encryptedString : null,
|
|
||||||
username: cipher.login.username ? cipher.login.username.encryptedString : null,
|
|
||||||
password: cipher.login.password ? cipher.login.password.encryptedString : null,
|
|
||||||
totp: cipher.login.totp ? cipher.login.totp.encryptedString : null
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case constantsService.cipherType.secureNote:
|
|
||||||
this.secureNote = {
|
|
||||||
type: cipher.secureNote.type
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case constantsService.cipherType.card:
|
|
||||||
this.card = {
|
|
||||||
cardholderName: cipher.card.cardholderName ? cipher.card.cardholderName.encryptedString : null,
|
|
||||||
brand: cipher.card.brand ? cipher.card.brand.encryptedString : null,
|
|
||||||
number: cipher.card.number ? cipher.card.number.encryptedString : null,
|
|
||||||
expMonth: cipher.card.expMonth ? cipher.card.expMonth.encryptedString : null,
|
|
||||||
expYear: cipher.card.expYear ? cipher.card.expYear.encryptedString : null,
|
|
||||||
code: cipher.card.code ? cipher.card.code.encryptedString : null
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case constantsService.cipherType.identity:
|
|
||||||
this.identity = {
|
|
||||||
title: cipher.identity.title ? cipher.identity.title.encryptedString : null,
|
|
||||||
firstName: cipher.identity.firstName ? cipher.identity.firstName.encryptedString : null,
|
|
||||||
middleName: cipher.identity.middleName ? cipher.identity.middleName.encryptedString : null,
|
|
||||||
lastName: cipher.identity.lastName ? cipher.identity.lastName.encryptedString : null,
|
|
||||||
address1: cipher.identity.address1 ? cipher.identity.address1.encryptedString : null,
|
|
||||||
address2: cipher.identity.address2 ? cipher.identity.address2.encryptedString : null,
|
|
||||||
address3: cipher.identity.address3 ? cipher.identity.address3.encryptedString : null,
|
|
||||||
city: cipher.identity.city ? cipher.identity.city.encryptedString : null,
|
|
||||||
state: cipher.identity.state ? cipher.identity.state.encryptedString : null,
|
|
||||||
postalCode: cipher.identity.postalCode ? cipher.identity.postalCode.encryptedString : null,
|
|
||||||
country: cipher.identity.country ? cipher.identity.country.encryptedString : null,
|
|
||||||
company: cipher.identity.company ? cipher.identity.company.encryptedString : null,
|
|
||||||
email: cipher.identity.email ? cipher.identity.email.encryptedString : null,
|
|
||||||
phone: cipher.identity.phone ? cipher.identity.phone.encryptedString : null,
|
|
||||||
ssn: cipher.identity.ssn ? cipher.identity.ssn.encryptedString : null,
|
|
||||||
username: cipher.identity.username ? cipher.identity.username.encryptedString : null,
|
|
||||||
passportNumber: cipher.identity.passportNumber ? cipher.identity.passportNumber.encryptedString : null,
|
|
||||||
licenseNumber: cipher.identity.licenseNumber ? cipher.identity.licenseNumber.encryptedString : null
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cipher.fields) {
|
|
||||||
this.fields = [];
|
|
||||||
for (var i = 0; i < cipher.fields.length; i++) {
|
|
||||||
this.fields.push({
|
|
||||||
type: cipher.fields[i].type,
|
|
||||||
name: cipher.fields[i].name ? cipher.fields[i].name.encryptedString : null,
|
|
||||||
value: cipher.fields[i].value ? cipher.fields[i].value.encryptedString : null,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var FolderRequest = function (folder) {
|
|
||||||
this.name = folder.name ? folder.name.encryptedString : null;
|
|
||||||
};
|
|
||||||
|
|
||||||
var TokenRequest = function (email, masterPasswordHash, provider, token, remember, device) {
|
|
||||||
this.email = email;
|
|
||||||
this.masterPasswordHash = masterPasswordHash;
|
|
||||||
this.token = token;
|
|
||||||
this.provider = provider;
|
|
||||||
this.remember = remember === true;
|
|
||||||
this.device = null;
|
|
||||||
if (device) {
|
|
||||||
this.device = device;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
TokenRequest.prototype.toIdentityToken = function () {
|
|
||||||
var obj = {
|
|
||||||
grant_type: 'password',
|
|
||||||
username: this.email,
|
|
||||||
password: this.masterPasswordHash,
|
|
||||||
scope: 'api offline_access',
|
|
||||||
client_id: 'browser'
|
|
||||||
};
|
|
||||||
|
|
||||||
if (this.device) {
|
|
||||||
obj.deviceType = this.device.type;
|
|
||||||
obj.deviceIdentifier = this.device.identifier;
|
|
||||||
obj.deviceName = this.device.name;
|
|
||||||
obj.devicePushToken = this.device.pushToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.token && this.provider !== null && (typeof this.provider !== 'undefined')) {
|
|
||||||
obj.twoFactorToken = this.token;
|
|
||||||
obj.twoFactorProvider = this.provider;
|
|
||||||
obj.twoFactorRemember = this.remember ? '1' : '0';
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
};
|
|
||||||
|
|
||||||
var RegisterRequest = function (email, masterPasswordHash, masterPasswordHint, key) {
|
|
||||||
this.name = null;
|
|
||||||
this.email = email;
|
|
||||||
this.masterPasswordHash = masterPasswordHash;
|
|
||||||
this.masterPasswordHint = masterPasswordHint ? masterPasswordHint : null;
|
|
||||||
this.key = key;
|
|
||||||
};
|
|
||||||
|
|
||||||
var PasswordHintRequest = function (email) {
|
|
||||||
this.email = email;
|
|
||||||
};
|
|
||||||
|
|
||||||
var TwoFactorEmailRequest = function (email, masterPasswordHash) {
|
|
||||||
this.email = email;
|
|
||||||
this.masterPasswordHash = masterPasswordHash;
|
|
||||||
};
|
|
||||||
|
|
||||||
var DeviceTokenRequest = function () {
|
|
||||||
this.pushToken = null;
|
|
||||||
};
|
|
||||||
|
|
||||||
var DeviceRequest = function (appId, utilsService) {
|
|
||||||
this.type = utilsService.getDeviceType();
|
|
||||||
this.name = utilsService.getBrowser();
|
|
||||||
this.identifier = appId;
|
|
||||||
this.pushToken = null;
|
|
||||||
};
|
|
@ -1,169 +0,0 @@
|
|||||||
var CipherResponse = function (response) {
|
|
||||||
this.id = response.Id;
|
|
||||||
this.organizationId = response.OrganizationId;
|
|
||||||
this.folderId = response.FolderId;
|
|
||||||
this.type = response.Type;
|
|
||||||
this.favorite = response.Favorite;
|
|
||||||
this.edit = response.Edit;
|
|
||||||
this.organizationUseTotp = response.OrganizationUseTotp;
|
|
||||||
this.data = response.Data;
|
|
||||||
this.revisionDate = response.RevisionDate;
|
|
||||||
|
|
||||||
if (response.Attachments) {
|
|
||||||
this.attachments = [];
|
|
||||||
for (var i = 0; i < response.Attachments.length; i++) {
|
|
||||||
this.attachments.push(new AttachmentResponse(response.Attachments[i]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var FolderResponse = function (response) {
|
|
||||||
this.id = response.Id;
|
|
||||||
this.name = response.Name;
|
|
||||||
this.revisionDate = response.RevisionDate;
|
|
||||||
};
|
|
||||||
|
|
||||||
var ProfileResponse = function (response) {
|
|
||||||
this.id = response.Id;
|
|
||||||
this.name = response.Name;
|
|
||||||
this.email = response.Email;
|
|
||||||
this.emailVerified = response.EmailVerified;
|
|
||||||
this.masterPasswordHint = response.MasterPasswordHint;
|
|
||||||
this.premium = response.Premium;
|
|
||||||
this.culture = response.Culture;
|
|
||||||
this.twoFactorEnabled = response.TwoFactorEnabled;
|
|
||||||
this.key = response.Key;
|
|
||||||
this.privateKey = response.PrivateKey;
|
|
||||||
this.securityStamp = response.SecurityStamp;
|
|
||||||
|
|
||||||
this.organizations = [];
|
|
||||||
if (response.Organizations) {
|
|
||||||
for (var i = 0; i < response.Organizations.length; i++) {
|
|
||||||
this.organizations.push(new ProfileOrganizationResponse(response.Organizations[i]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var KeysResponse = function (response) {
|
|
||||||
this.privateKey = response.PrivateKey;
|
|
||||||
this.publicKey = response.PublicKey;
|
|
||||||
};
|
|
||||||
|
|
||||||
var ProfileOrganizationResponse = function (response) {
|
|
||||||
this.id = response.Id;
|
|
||||||
this.name = response.Name;
|
|
||||||
this.useGroups = response.UseGroups;
|
|
||||||
this.useDirectory = response.UseDirectory;
|
|
||||||
this.useTotp = response.UseTotp;
|
|
||||||
this.seats = response.Seats;
|
|
||||||
this.maxCollections = response.MaxCollections;
|
|
||||||
this.maxStorageGb = response.MaxStorageGb;
|
|
||||||
this.key = response.Key;
|
|
||||||
this.status = response.Status;
|
|
||||||
this.type = response.Type;
|
|
||||||
};
|
|
||||||
|
|
||||||
var AttachmentResponse = function (response) {
|
|
||||||
this.id = response.Id;
|
|
||||||
this.url = response.Url;
|
|
||||||
this.fileName = response.FileName;
|
|
||||||
this.size = response.Size;
|
|
||||||
this.sizeName = response.SizeName;
|
|
||||||
};
|
|
||||||
|
|
||||||
var IdentityTokenResponse = function (response) {
|
|
||||||
this.accessToken = response.access_token;
|
|
||||||
this.expiresIn = response.expires_in;
|
|
||||||
this.refreshToken = response.refresh_token;
|
|
||||||
this.tokenType = response.token_type;
|
|
||||||
|
|
||||||
this.privateKey = response.PrivateKey;
|
|
||||||
this.key = response.Key;
|
|
||||||
this.twoFactorToken = response.TwoFactorToken;
|
|
||||||
};
|
|
||||||
|
|
||||||
var ListResponse = function (data) {
|
|
||||||
this.data = data;
|
|
||||||
};
|
|
||||||
|
|
||||||
var ErrorResponse = function (response, identityResponse) {
|
|
||||||
var errorModel = null;
|
|
||||||
if (identityResponse && identityResponse === true && response.responseJSON && response.responseJSON.ErrorModel) {
|
|
||||||
errorModel = response.responseJSON.ErrorModel;
|
|
||||||
}
|
|
||||||
else if (response.responseJSON) {
|
|
||||||
errorModel = response.responseJSON;
|
|
||||||
}
|
|
||||||
else if (response.responseText && response.responseText.indexOf('{') === 0) {
|
|
||||||
errorModel = JSON.parse(response.responseText);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (errorModel) {
|
|
||||||
this.message = errorModel.Message;
|
|
||||||
this.validationErrors = errorModel.ValidationErrors;
|
|
||||||
}
|
|
||||||
this.statusCode = response.status;
|
|
||||||
};
|
|
||||||
|
|
||||||
var DeviceResponse = function (response) {
|
|
||||||
this.id = response.Id;
|
|
||||||
this.name = response.Name;
|
|
||||||
this.identifier = response.Identifier;
|
|
||||||
this.type = response.Type;
|
|
||||||
this.creationDate = response.CreationDate;
|
|
||||||
};
|
|
||||||
|
|
||||||
var CipherHistoryResponse = function (response) {
|
|
||||||
this.revised = [];
|
|
||||||
|
|
||||||
var revised = response.Revised;
|
|
||||||
for (var i = 0; i < revised.length; i++) {
|
|
||||||
this.revised.push(new CipherResponse(revised[i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.deleted = response.Deleted;
|
|
||||||
};
|
|
||||||
|
|
||||||
var DomainsResponse = function (response) {
|
|
||||||
var GlobalDomainResponse = function (response) {
|
|
||||||
this.type = response.Type;
|
|
||||||
this.domains = response.Domains;
|
|
||||||
this.excluded = response.Excluded;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.equivalentDomains = response.EquivalentDomains;
|
|
||||||
this.globalEquivalentDomains = [];
|
|
||||||
|
|
||||||
var globalEquivalentDomains = response.GlobalEquivalentDomains;
|
|
||||||
if (!globalEquivalentDomains) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (var i = 0; i < globalEquivalentDomains.length; i++) {
|
|
||||||
this.globalEquivalentDomains.push(new GlobalDomainResponse(globalEquivalentDomains[i]));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var SyncResponse = function (response) {
|
|
||||||
if (response.Profile) {
|
|
||||||
this.profile = new ProfileResponse(response.Profile);
|
|
||||||
}
|
|
||||||
|
|
||||||
var i;
|
|
||||||
this.folders = [];
|
|
||||||
if (response.Folders) {
|
|
||||||
for (i = 0; i < response.Folders.length; i++) {
|
|
||||||
this.folders.push(new FolderResponse(response.Folders[i]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.ciphers = [];
|
|
||||||
if (response.Ciphers) {
|
|
||||||
for (i = 0; i < response.Ciphers.length; i++) {
|
|
||||||
this.ciphers.push(new CipherResponse(response.Ciphers[i]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response.Domains) {
|
|
||||||
this.domains = new DomainsResponse(response.Domains);
|
|
||||||
}
|
|
||||||
};
|
|
20
src/models/data/attachmentData.ts
Normal file
20
src/models/data/attachmentData.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { AttachmentResponse } from '../response/attachmentResponse';
|
||||||
|
|
||||||
|
class AttachmentData {
|
||||||
|
id: string;
|
||||||
|
url: string;
|
||||||
|
fileName: string;
|
||||||
|
size: number;
|
||||||
|
sizeName: string;
|
||||||
|
|
||||||
|
constructor(response: AttachmentResponse) {
|
||||||
|
this.id = response.id;
|
||||||
|
this.url = response.url;
|
||||||
|
this.fileName = response.fileName;
|
||||||
|
this.size = response.size;
|
||||||
|
this.sizeName = response.sizeName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { AttachmentData };
|
||||||
|
(window as any).AttachmentData = AttachmentData;
|
20
src/models/data/cardData.ts
Normal file
20
src/models/data/cardData.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
class CardData {
|
||||||
|
cardholderName: string;
|
||||||
|
brand: string;
|
||||||
|
number: string;
|
||||||
|
expMonth: string;
|
||||||
|
expYear: string;
|
||||||
|
code: string;
|
||||||
|
|
||||||
|
constructor(data: any) {
|
||||||
|
this.cardholderName = data.CardholderName;
|
||||||
|
this.brand = data.Brand;
|
||||||
|
this.number = data.Number;
|
||||||
|
this.expMonth = data.ExpMonth;
|
||||||
|
this.expYear = data.ExpYear;
|
||||||
|
this.code = data.Code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { CardData };
|
||||||
|
(window as any).CardData = CardData;
|
80
src/models/data/cipherData.ts
Normal file
80
src/models/data/cipherData.ts
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
import { CipherType } from '../../enums/cipherType.enum';
|
||||||
|
|
||||||
|
import { AttachmentData } from './attachmentData';
|
||||||
|
import { CardData } from './cardData';
|
||||||
|
import { FieldData } from './fieldData';
|
||||||
|
import { IdentityData } from './identityData';
|
||||||
|
import { LoginData } from './loginData';
|
||||||
|
import { SecureNoteData } from './secureNoteData';
|
||||||
|
|
||||||
|
import { CipherResponse } from '../response/cipherResponse';
|
||||||
|
|
||||||
|
class CipherData {
|
||||||
|
id: string;
|
||||||
|
organizationId: string;
|
||||||
|
folderId: string;
|
||||||
|
userId: string;
|
||||||
|
edit: boolean;
|
||||||
|
organizationUseTotp: boolean;
|
||||||
|
favorite: boolean;
|
||||||
|
revisionDate: string;
|
||||||
|
type: CipherType;
|
||||||
|
sizeName: string;
|
||||||
|
name: string;
|
||||||
|
notes: string;
|
||||||
|
login?: LoginData;
|
||||||
|
secureNote?: SecureNoteData;
|
||||||
|
card?: CardData;
|
||||||
|
identity?: IdentityData;
|
||||||
|
fields?: FieldData[];
|
||||||
|
attachments?: AttachmentData[];
|
||||||
|
|
||||||
|
constructor(response: CipherResponse, userId: string) {
|
||||||
|
this.id = response.id;
|
||||||
|
this.organizationId = response.organizationId;
|
||||||
|
this.folderId = response.folderId;
|
||||||
|
this.userId = userId;
|
||||||
|
this.edit = response.edit;
|
||||||
|
this.organizationUseTotp = response.organizationUseTotp;
|
||||||
|
this.favorite = response.favorite;
|
||||||
|
this.revisionDate = response.revisionDate;
|
||||||
|
this.type = response.type;
|
||||||
|
|
||||||
|
this.name = response.data.Name;
|
||||||
|
this.notes = response.data.Notes;
|
||||||
|
|
||||||
|
switch (this.type) {
|
||||||
|
case CipherType.Login:
|
||||||
|
this.login = new LoginData(response.data);
|
||||||
|
break;
|
||||||
|
case CipherType.SecureNote:
|
||||||
|
this.secureNote = new SecureNoteData(response.data);
|
||||||
|
break;
|
||||||
|
case CipherType.Card:
|
||||||
|
this.card = new CardData(response.data);
|
||||||
|
break;
|
||||||
|
case CipherType.Identity:
|
||||||
|
this.identity = new IdentityData(response.data);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.data.Fields != null) {
|
||||||
|
this.fields = [];
|
||||||
|
for (const field of response.data.Fields) {
|
||||||
|
this.fields.push(new FieldData(field));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.attachments != null) {
|
||||||
|
this.attachments = [];
|
||||||
|
for (const attachment of response.attachments) {
|
||||||
|
this.attachments.push(new AttachmentData(attachment));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { CipherData };
|
||||||
|
(window as any).CipherData = CipherData;
|
14
src/models/data/fieldData.ts
Normal file
14
src/models/data/fieldData.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
class FieldData {
|
||||||
|
type: number; // TODO: enum
|
||||||
|
name: string;
|
||||||
|
value: string;
|
||||||
|
|
||||||
|
constructor(response: any) {
|
||||||
|
this.type = response.Type;
|
||||||
|
this.name = response.Name;
|
||||||
|
this.value = response.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { FieldData };
|
||||||
|
(window as any).FieldData = FieldData;
|
18
src/models/data/folderData.ts
Normal file
18
src/models/data/folderData.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { FolderResponse } from '../response/folderResponse';
|
||||||
|
|
||||||
|
class FolderData {
|
||||||
|
id: string;
|
||||||
|
userId: string;
|
||||||
|
name: string;
|
||||||
|
revisionDate: string;
|
||||||
|
|
||||||
|
constructor(response: FolderResponse, userId: string) {
|
||||||
|
this.userId = userId;
|
||||||
|
this.name = response.name;
|
||||||
|
this.id = response.id;
|
||||||
|
this.revisionDate = response.revisionDate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { FolderData };
|
||||||
|
(window as any).FolderData = FolderData;
|
44
src/models/data/identityData.ts
Normal file
44
src/models/data/identityData.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
class IdentityData {
|
||||||
|
title: string;
|
||||||
|
firstName: string;
|
||||||
|
middleName: string;
|
||||||
|
lastName: string;
|
||||||
|
address1: string;
|
||||||
|
address2: string;
|
||||||
|
address3: string;
|
||||||
|
city: string;
|
||||||
|
state: string;
|
||||||
|
postalCode: string;
|
||||||
|
country: string;
|
||||||
|
company: string;
|
||||||
|
email: string;
|
||||||
|
phone: string;
|
||||||
|
ssn: string;
|
||||||
|
username: string;
|
||||||
|
passportNumber: string;
|
||||||
|
licenseNumber: string;
|
||||||
|
|
||||||
|
constructor(data: any) {
|
||||||
|
this.title = data.Title;
|
||||||
|
this.firstName = data.FirstName;
|
||||||
|
this.middleName = data.MiddleName;
|
||||||
|
this.lastName = data.LastName;
|
||||||
|
this.address1 = data.Address1;
|
||||||
|
this.address2 = data.Address2;
|
||||||
|
this.address3 = data.Address3;
|
||||||
|
this.city = data.City;
|
||||||
|
this.state = data.State;
|
||||||
|
this.postalCode = data.PostalCode;
|
||||||
|
this.country = data.Country;
|
||||||
|
this.company = data.Company;
|
||||||
|
this.email = data.Email;
|
||||||
|
this.phone = data.Phone;
|
||||||
|
this.ssn = data.SSN;
|
||||||
|
this.username = data.Username;
|
||||||
|
this.passportNumber = data.PassportNumber;
|
||||||
|
this.licenseNumber = data.LicenseNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { IdentityData };
|
||||||
|
(window as any).IdentityData = IdentityData;
|
16
src/models/data/loginData.ts
Normal file
16
src/models/data/loginData.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
class LoginData {
|
||||||
|
uri: string;
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
totp: string;
|
||||||
|
|
||||||
|
constructor(data: any) {
|
||||||
|
this.uri = data.Uri;
|
||||||
|
this.username = data.Username;
|
||||||
|
this.password = data.Password;
|
||||||
|
this.totp = data.Totp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { LoginData };
|
||||||
|
(window as any).LoginData = LoginData;
|
10
src/models/data/secureNoteData.ts
Normal file
10
src/models/data/secureNoteData.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
class SecureNoteData {
|
||||||
|
type: number; // TODO: enum
|
||||||
|
|
||||||
|
constructor(data: any) {
|
||||||
|
this.type = data.Type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { SecureNoteData };
|
||||||
|
(window as any).SecureNoteData = SecureNoteData;
|
@ -1,119 +0,0 @@
|
|||||||
var FolderData = function (response, userId) {
|
|
||||||
this.id = response.id;
|
|
||||||
this.userId = userId;
|
|
||||||
|
|
||||||
if (response instanceof FolderResponse) {
|
|
||||||
this.name = response.name;
|
|
||||||
}
|
|
||||||
else if (response instanceof CipherResponse) {
|
|
||||||
this.name = response.data.Name;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw 'unsupported instance';
|
|
||||||
}
|
|
||||||
|
|
||||||
this.revisionDate = response.revisionDate;
|
|
||||||
};
|
|
||||||
|
|
||||||
var CipherData = function (response, userId) {
|
|
||||||
this.id = response.id;
|
|
||||||
this.organizationId = response.organizationId;
|
|
||||||
this.folderId = response.folderId;
|
|
||||||
this.userId = userId;
|
|
||||||
this.edit = response.edit;
|
|
||||||
this.organizationUseTotp = response.organizationUseTotp;
|
|
||||||
this.favorite = response.favorite;
|
|
||||||
this.revisionDate = response.revisionDate;
|
|
||||||
this.type = response.type;
|
|
||||||
|
|
||||||
this.name = response.data.Name;
|
|
||||||
this.notes = response.notes = response.data.Notes;
|
|
||||||
|
|
||||||
var constantsService = chrome.extension.getBackgroundPage().bg_constantsService;
|
|
||||||
switch (this.type) {
|
|
||||||
case constantsService.cipherType.login:
|
|
||||||
this.login = new LoginData(response.data);
|
|
||||||
break;
|
|
||||||
case constantsService.cipherType.secureNote:
|
|
||||||
this.secureNote = new SecureNoteData(response.data);
|
|
||||||
break;
|
|
||||||
case constantsService.cipherType.card:
|
|
||||||
this.card = new CardData(response.data);
|
|
||||||
break;
|
|
||||||
case constantsService.cipherType.identity:
|
|
||||||
this.identity = new IdentityData(response.data);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
var i;
|
|
||||||
if (response.data.Fields) {
|
|
||||||
this.fields = [];
|
|
||||||
for (i = 0; i < response.data.Fields.length; i++) {
|
|
||||||
this.fields.push(new FieldData(response.data.Fields[i]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response.attachments) {
|
|
||||||
this.attachments = [];
|
|
||||||
for (i = 0; i < response.attachments.length; i++) {
|
|
||||||
this.attachments.push(new AttachmentData(response.attachments[i]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var AttachmentData = function (response) {
|
|
||||||
this.id = response.id;
|
|
||||||
this.url = response.url;
|
|
||||||
this.fileName = response.fileName;
|
|
||||||
this.size = response.size;
|
|
||||||
this.sizeName = response.sizeName;
|
|
||||||
};
|
|
||||||
|
|
||||||
var FieldData = function (response) {
|
|
||||||
this.type = response.Type;
|
|
||||||
this.name = response.Name;
|
|
||||||
this.value = response.Value;
|
|
||||||
};
|
|
||||||
|
|
||||||
var LoginData = function (data) {
|
|
||||||
this.uri = data.Uri;
|
|
||||||
this.username = data.Username;
|
|
||||||
this.password = data.Password;
|
|
||||||
this.totp = data.Totp;
|
|
||||||
};
|
|
||||||
|
|
||||||
var IdentityData = function (data) {
|
|
||||||
this.title = data.Title;
|
|
||||||
this.firstName = data.FirstName;
|
|
||||||
this.middleName = data.MiddleName;
|
|
||||||
this.lastName = data.LastName;
|
|
||||||
this.address1 = data.Address1;
|
|
||||||
this.address2 = data.Address2;
|
|
||||||
this.address3 = data.Address3;
|
|
||||||
this.city = data.City;
|
|
||||||
this.state = data.State;
|
|
||||||
this.postalCode = data.PostalCode;
|
|
||||||
this.country = data.Country;
|
|
||||||
this.company = data.Company;
|
|
||||||
this.email = data.Email;
|
|
||||||
this.phone = data.Phone;
|
|
||||||
this.ssn = data.SSN;
|
|
||||||
this.username = data.Username;
|
|
||||||
this.passportNumber = data.PassportNumber;
|
|
||||||
this.licenseNumber = data.LicenseNumber;
|
|
||||||
};
|
|
||||||
|
|
||||||
var SecureNoteData = function (data) {
|
|
||||||
this.type = data.Type;
|
|
||||||
};
|
|
||||||
|
|
||||||
var CardData = function (data) {
|
|
||||||
this.cardholderName = data.CardholderName;
|
|
||||||
this.brand = data.Brand;
|
|
||||||
this.number = data.Number;
|
|
||||||
this.expMonth = data.ExpMonth;
|
|
||||||
this.expYear = data.ExpYear;
|
|
||||||
this.code = data.Code;
|
|
||||||
};
|
|
43
src/models/domain/attachment.ts
Normal file
43
src/models/domain/attachment.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import { AttachmentData } from '../data/attachmentData';
|
||||||
|
|
||||||
|
import { CipherString } from './cipherString';
|
||||||
|
import Domain from './domain';
|
||||||
|
|
||||||
|
class Attachment extends Domain {
|
||||||
|
id: string;
|
||||||
|
url: string;
|
||||||
|
size: number;
|
||||||
|
sizeName: string;
|
||||||
|
fileName: CipherString;
|
||||||
|
|
||||||
|
constructor(obj?: AttachmentData, alreadyEncrypted: boolean = false) {
|
||||||
|
super();
|
||||||
|
if (obj == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.size = obj.size;
|
||||||
|
this.buildDomainModel(this, obj, {
|
||||||
|
id: null,
|
||||||
|
url: null,
|
||||||
|
sizeName: null,
|
||||||
|
fileName: null,
|
||||||
|
}, alreadyEncrypted, ['id', 'url', 'sizeName']);
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypt(orgId: string): Promise<any> {
|
||||||
|
const model = {
|
||||||
|
id: this.id,
|
||||||
|
size: this.size,
|
||||||
|
sizeName: this.sizeName,
|
||||||
|
url: this.url,
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.decryptObj(model, {
|
||||||
|
fileName: null,
|
||||||
|
}, orgId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Attachment };
|
||||||
|
(window as any).Attachment = Attachment;
|
20
src/models/domain/autofillField.ts
Normal file
20
src/models/domain/autofillField.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
export default class AutofillField {
|
||||||
|
opid: string;
|
||||||
|
elementNumber: number;
|
||||||
|
visible: boolean;
|
||||||
|
viewable: boolean;
|
||||||
|
htmlID: string;
|
||||||
|
htmlName: string;
|
||||||
|
htmlClass: string;
|
||||||
|
labelRight: string;
|
||||||
|
labelLeft: string;
|
||||||
|
'label-tag': string;
|
||||||
|
placeholder: string;
|
||||||
|
type: string;
|
||||||
|
value: string;
|
||||||
|
disabled: boolean;
|
||||||
|
readonly: boolean;
|
||||||
|
onePasswordFieldType: string;
|
||||||
|
form: string;
|
||||||
|
autoCompleteType: string;
|
||||||
|
}
|
7
src/models/domain/autofillForm.ts
Normal file
7
src/models/domain/autofillForm.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export default class AutofillForm {
|
||||||
|
opid: string;
|
||||||
|
htmlName: string;
|
||||||
|
htmlID: string;
|
||||||
|
htmlAction: string;
|
||||||
|
htmlMethod: string;
|
||||||
|
}
|
13
src/models/domain/autofillPageDetails.ts
Normal file
13
src/models/domain/autofillPageDetails.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import AutofillField from './autofillField';
|
||||||
|
import AutofillForm from './autofillForm';
|
||||||
|
|
||||||
|
export default class AutofillPageDetails {
|
||||||
|
documentUUID: string;
|
||||||
|
title: string;
|
||||||
|
url: string;
|
||||||
|
documentUrl: string;
|
||||||
|
tabUrl: string;
|
||||||
|
forms: { [id: string]: AutofillForm; };
|
||||||
|
fields: AutofillField[];
|
||||||
|
collectedTimestamp: number;
|
||||||
|
}
|
12
src/models/domain/autofillScript.ts
Normal file
12
src/models/domain/autofillScript.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
export default class AutofillScript {
|
||||||
|
script: string[][] = [];
|
||||||
|
documentUUID: any = {};
|
||||||
|
properties: any = {};
|
||||||
|
options: any = {};
|
||||||
|
metadata: any = {};
|
||||||
|
autosubmit: any = null;
|
||||||
|
|
||||||
|
constructor(documentUUID: string) {
|
||||||
|
this.documentUUID = documentUUID;
|
||||||
|
}
|
||||||
|
}
|
43
src/models/domain/card.ts
Normal file
43
src/models/domain/card.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import { CardData } from '../data/cardData';
|
||||||
|
|
||||||
|
import { CipherString } from './cipherString';
|
||||||
|
import Domain from './domain';
|
||||||
|
|
||||||
|
class Card extends Domain {
|
||||||
|
cardholderName: CipherString;
|
||||||
|
brand: CipherString;
|
||||||
|
number: CipherString;
|
||||||
|
expMonth: CipherString;
|
||||||
|
expYear: CipherString;
|
||||||
|
code: CipherString;
|
||||||
|
|
||||||
|
constructor(obj?: CardData, alreadyEncrypted: boolean = false) {
|
||||||
|
super();
|
||||||
|
if (obj == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.buildDomainModel(this, obj, {
|
||||||
|
cardholderName: null,
|
||||||
|
brand: null,
|
||||||
|
number: null,
|
||||||
|
expMonth: null,
|
||||||
|
expYear: null,
|
||||||
|
code: null,
|
||||||
|
}, alreadyEncrypted, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypt(orgId: string): Promise<any> {
|
||||||
|
return this.decryptObj({}, {
|
||||||
|
cardholderName: null,
|
||||||
|
brand: null,
|
||||||
|
number: null,
|
||||||
|
expMonth: null,
|
||||||
|
expYear: null,
|
||||||
|
code: null,
|
||||||
|
}, orgId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Card };
|
||||||
|
(window as any).Card = Card;
|
181
src/models/domain/cipher.ts
Normal file
181
src/models/domain/cipher.ts
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
import { CipherType } from '../../enums/cipherType.enum';
|
||||||
|
|
||||||
|
import { CipherData } from '../data/cipherData';
|
||||||
|
|
||||||
|
import { Attachment } from './attachment';
|
||||||
|
import { Card } from './card';
|
||||||
|
import { CipherString } from './cipherString';
|
||||||
|
import Domain from './domain';
|
||||||
|
import { Field } from './field';
|
||||||
|
import { Identity } from './identity';
|
||||||
|
import { Login } from './login';
|
||||||
|
import { SecureNote } from './secureNote';
|
||||||
|
|
||||||
|
import UtilsService from '../../services/utils.service';
|
||||||
|
|
||||||
|
class Cipher extends Domain {
|
||||||
|
id: string;
|
||||||
|
organizationId: string;
|
||||||
|
folderId: string;
|
||||||
|
name: CipherString;
|
||||||
|
notes: CipherString;
|
||||||
|
type: CipherType;
|
||||||
|
favorite: boolean;
|
||||||
|
organizationUseTotp: boolean;
|
||||||
|
edit: boolean;
|
||||||
|
localData: any;
|
||||||
|
login: Login;
|
||||||
|
identity: Identity;
|
||||||
|
card: Card;
|
||||||
|
secureNote: SecureNote;
|
||||||
|
attachments: Attachment[];
|
||||||
|
fields: Field[];
|
||||||
|
|
||||||
|
constructor(obj?: CipherData, alreadyEncrypted: boolean = false, localData: any = null) {
|
||||||
|
super();
|
||||||
|
if (obj == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.buildDomainModel(this, obj, {
|
||||||
|
id: null,
|
||||||
|
organizationId: null,
|
||||||
|
folderId: null,
|
||||||
|
name: null,
|
||||||
|
notes: null,
|
||||||
|
}, alreadyEncrypted, ['id', 'organizationId', 'folderId']);
|
||||||
|
|
||||||
|
this.type = obj.type;
|
||||||
|
this.favorite = obj.favorite;
|
||||||
|
this.organizationUseTotp = obj.organizationUseTotp;
|
||||||
|
this.edit = obj.edit;
|
||||||
|
|
||||||
|
switch (this.type) {
|
||||||
|
case CipherType.Login:
|
||||||
|
this.login = new Login(obj.login, alreadyEncrypted);
|
||||||
|
break;
|
||||||
|
case CipherType.SecureNote:
|
||||||
|
this.secureNote = new SecureNote(obj.secureNote, alreadyEncrypted);
|
||||||
|
break;
|
||||||
|
case CipherType.Card:
|
||||||
|
this.card = new Card(obj.card, alreadyEncrypted);
|
||||||
|
break;
|
||||||
|
case CipherType.Identity:
|
||||||
|
this.identity = new Identity(obj.identity, alreadyEncrypted);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj.attachments != null) {
|
||||||
|
this.attachments = [];
|
||||||
|
for (const attachment of obj.attachments) {
|
||||||
|
this.attachments.push(new Attachment(attachment, alreadyEncrypted));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.attachments = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj.fields != null) {
|
||||||
|
this.fields = [];
|
||||||
|
for (const field of obj.fields) {
|
||||||
|
this.fields.push(new Field(field, alreadyEncrypted));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.fields = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async decrypt(): Promise<any> {
|
||||||
|
const model = {
|
||||||
|
id: this.id,
|
||||||
|
organizationId: this.organizationId,
|
||||||
|
folderId: this.folderId,
|
||||||
|
favorite: this.favorite,
|
||||||
|
type: this.type,
|
||||||
|
localData: this.localData,
|
||||||
|
login: null as any,
|
||||||
|
card: null as any,
|
||||||
|
identity: null as any,
|
||||||
|
secureNote: null as any,
|
||||||
|
subTitle: null as string,
|
||||||
|
attachments: null as any[],
|
||||||
|
fields: null as any[],
|
||||||
|
};
|
||||||
|
|
||||||
|
await this.decryptObj(model, {
|
||||||
|
name: null,
|
||||||
|
notes: null,
|
||||||
|
}, this.organizationId);
|
||||||
|
|
||||||
|
switch (this.type) {
|
||||||
|
case CipherType.Login:
|
||||||
|
model.login = await this.login.decrypt(this.organizationId);
|
||||||
|
model.subTitle = model.login.username;
|
||||||
|
if (model.login.uri) {
|
||||||
|
model.login.domain = UtilsService.getDomain(model.login.uri);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CipherType.SecureNote:
|
||||||
|
model.secureNote = await this.secureNote.decrypt(this.organizationId);
|
||||||
|
model.subTitle = null;
|
||||||
|
break;
|
||||||
|
case CipherType.Card:
|
||||||
|
model.card = await this.card.decrypt(this.organizationId);
|
||||||
|
model.subTitle = model.card.brand;
|
||||||
|
if (model.card.number && model.card.number.length >= 4) {
|
||||||
|
if (model.subTitle !== '') {
|
||||||
|
model.subTitle += ', ';
|
||||||
|
}
|
||||||
|
model.subTitle += ('*' + model.card.number.substr(model.card.number.length - 4));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CipherType.Identity:
|
||||||
|
model.identity = await this.identity.decrypt(this.organizationId);
|
||||||
|
model.subTitle = '';
|
||||||
|
if (model.identity.firstName) {
|
||||||
|
model.subTitle = model.identity.firstName;
|
||||||
|
}
|
||||||
|
if (model.identity.lastName) {
|
||||||
|
if (model.subTitle !== '') {
|
||||||
|
model.subTitle += ' ';
|
||||||
|
}
|
||||||
|
model.subTitle += model.identity.lastName;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const orgId = this.organizationId;
|
||||||
|
|
||||||
|
if (this.attachments != null) {
|
||||||
|
const attachments: any[] = [];
|
||||||
|
await this.attachments.reduce((promise, attachment) => {
|
||||||
|
return promise.then(() => {
|
||||||
|
return attachment.decrypt(orgId);
|
||||||
|
}).then((decAttachment) => {
|
||||||
|
attachments.push(decAttachment);
|
||||||
|
});
|
||||||
|
}, Promise.resolve());
|
||||||
|
model.attachments = attachments;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.fields != null) {
|
||||||
|
const fields: any[] = [];
|
||||||
|
await this.fields.reduce((promise, field) => {
|
||||||
|
return promise.then(() => {
|
||||||
|
return field.decrypt(orgId);
|
||||||
|
}).then((decField) => {
|
||||||
|
fields.push(decField);
|
||||||
|
});
|
||||||
|
}, Promise.resolve());
|
||||||
|
model.fields = fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Cipher };
|
||||||
|
(window as any).Cipher = Cipher;
|
112
src/models/domain/cipherString.ts
Normal file
112
src/models/domain/cipherString.ts
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
import { EncryptionType } from '../../enums/encryptionType.enum';
|
||||||
|
import CryptoService from '../../services/crypto.service';
|
||||||
|
|
||||||
|
class CipherString {
|
||||||
|
encryptedString?: string;
|
||||||
|
encryptionType?: EncryptionType;
|
||||||
|
decryptedValue?: string;
|
||||||
|
cipherText?: string;
|
||||||
|
initializationVector?: string;
|
||||||
|
mac?: string;
|
||||||
|
cryptoService: CryptoService;
|
||||||
|
|
||||||
|
constructor(encryptedStringOrType: string | EncryptionType, ct?: string, iv?: string, mac?: string) {
|
||||||
|
this.cryptoService = chrome.extension.getBackgroundPage().bg_cryptoService as CryptoService;
|
||||||
|
|
||||||
|
if (ct != null) {
|
||||||
|
// ct and header
|
||||||
|
const encType = encryptedStringOrType as EncryptionType;
|
||||||
|
this.encryptedString = encType + '.' + ct;
|
||||||
|
|
||||||
|
// iv
|
||||||
|
if (iv != null) {
|
||||||
|
this.encryptedString += ('|' + iv);
|
||||||
|
}
|
||||||
|
|
||||||
|
// mac
|
||||||
|
if (mac != null) {
|
||||||
|
this.encryptedString += ('|' + mac);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.encryptionType = encType;
|
||||||
|
this.cipherText = ct;
|
||||||
|
this.initializationVector = iv;
|
||||||
|
this.mac = mac;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.encryptedString = encryptedStringOrType as string;
|
||||||
|
if (!this.encryptedString) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const headerPieces = this.encryptedString.split('.');
|
||||||
|
let encPieces: string[] = null;
|
||||||
|
|
||||||
|
if (headerPieces.length === 2) {
|
||||||
|
try {
|
||||||
|
this.encryptionType = parseInt(headerPieces[0], null);
|
||||||
|
encPieces = headerPieces[1].split('|');
|
||||||
|
} catch (e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
encPieces = this.encryptedString.split('|');
|
||||||
|
this.encryptionType = encPieces.length === 3 ? EncryptionType.AesCbc128_HmacSha256_B64 :
|
||||||
|
EncryptionType.AesCbc256_B64;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (this.encryptionType) {
|
||||||
|
case EncryptionType.AesCbc128_HmacSha256_B64:
|
||||||
|
case EncryptionType.AesCbc256_HmacSha256_B64:
|
||||||
|
if (encPieces.length !== 3) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.initializationVector = encPieces[0];
|
||||||
|
this.cipherText = encPieces[1];
|
||||||
|
this.mac = encPieces[2];
|
||||||
|
break;
|
||||||
|
case EncryptionType.AesCbc256_B64:
|
||||||
|
if (encPieces.length !== 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.initializationVector = encPieces[0];
|
||||||
|
this.cipherText = encPieces[1];
|
||||||
|
break;
|
||||||
|
case EncryptionType.Rsa2048_OaepSha256_B64:
|
||||||
|
case EncryptionType.Rsa2048_OaepSha1_B64:
|
||||||
|
if (encPieces.length !== 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.cipherText = encPieces[0];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypt(orgId: string) {
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
if (this.decryptedValue) {
|
||||||
|
return Promise.resolve(self.decryptedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.cryptoService.getOrgKey(orgId).then((orgKey: any) => {
|
||||||
|
return self.cryptoService.decrypt(self, orgKey);
|
||||||
|
}).then((decValue: any) => {
|
||||||
|
self.decryptedValue = decValue;
|
||||||
|
return self.decryptedValue;
|
||||||
|
}).catch(() => {
|
||||||
|
self.decryptedValue = '[error: cannot decrypt]';
|
||||||
|
return self.decryptedValue;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { CipherString };
|
||||||
|
(window as any).CipherString = CipherString;
|
46
src/models/domain/domain.ts
Normal file
46
src/models/domain/domain.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import { CipherString } from '../domain/cipherString';
|
||||||
|
|
||||||
|
export default abstract class Domain {
|
||||||
|
protected buildDomainModel(model: any, obj: any, map: any, alreadyEncrypted: boolean, notEncList: any[] = []) {
|
||||||
|
for (const prop in map) {
|
||||||
|
if (!map.hasOwnProperty(prop)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const objProp = obj[(map[prop] || prop)];
|
||||||
|
if (alreadyEncrypted === true || notEncList.indexOf(prop) > -1) {
|
||||||
|
model[prop] = objProp ? objProp : null;
|
||||||
|
} else {
|
||||||
|
model[prop] = objProp ? new CipherString(objProp) : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async decryptObj(model: any, map: any, orgId: string) {
|
||||||
|
const promises = [];
|
||||||
|
const self: any = this;
|
||||||
|
|
||||||
|
for (const prop in map) {
|
||||||
|
if (!map.hasOwnProperty(prop)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// tslint:disable-next-line
|
||||||
|
(function (theProp) {
|
||||||
|
const p = Promise.resolve().then(() => {
|
||||||
|
const mapProp = map[theProp] || theProp;
|
||||||
|
if (self[mapProp]) {
|
||||||
|
return self[mapProp].decrypt(orgId);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}).then((val: any) => {
|
||||||
|
model[theProp] = val;
|
||||||
|
});
|
||||||
|
promises.push(p);
|
||||||
|
})(prop);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Promise.all(promises);
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
}
|
8
src/models/domain/encryptedObject.ts
Normal file
8
src/models/domain/encryptedObject.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import SymmetricCryptoKey from './symmetricCryptoKey';
|
||||||
|
|
||||||
|
export default class EncryptedObject {
|
||||||
|
iv: Uint8Array;
|
||||||
|
ct: Uint8Array;
|
||||||
|
mac: Uint8Array;
|
||||||
|
key: SymmetricCryptoKey;
|
||||||
|
}
|
5
src/models/domain/environmentUrls.ts
Normal file
5
src/models/domain/environmentUrls.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export default class EnvironmentUrls {
|
||||||
|
base: string;
|
||||||
|
api: string;
|
||||||
|
identity: string;
|
||||||
|
}
|
39
src/models/domain/field.ts
Normal file
39
src/models/domain/field.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { FieldType } from '../../enums/fieldType.enum';
|
||||||
|
|
||||||
|
import { FieldData } from '../data/fieldData';
|
||||||
|
|
||||||
|
import { CipherString } from './cipherString';
|
||||||
|
import Domain from './domain';
|
||||||
|
|
||||||
|
class Field extends Domain {
|
||||||
|
name: CipherString;
|
||||||
|
vault: CipherString;
|
||||||
|
type: FieldType;
|
||||||
|
|
||||||
|
constructor(obj?: FieldData, alreadyEncrypted: boolean = false) {
|
||||||
|
super();
|
||||||
|
if (obj == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.type = obj.type;
|
||||||
|
this.buildDomainModel(this, obj, {
|
||||||
|
name: null,
|
||||||
|
value: null,
|
||||||
|
}, alreadyEncrypted, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypt(orgId: string): Promise<any> {
|
||||||
|
const model = {
|
||||||
|
type: this.type,
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.decryptObj(model, {
|
||||||
|
name: null,
|
||||||
|
value: null,
|
||||||
|
}, orgId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Field };
|
||||||
|
(window as any).Field = Field;
|
34
src/models/domain/folder.ts
Normal file
34
src/models/domain/folder.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import { FolderData } from '../data/folderData';
|
||||||
|
|
||||||
|
import { CipherString } from './cipherString';
|
||||||
|
import Domain from './domain';
|
||||||
|
|
||||||
|
class Folder extends Domain {
|
||||||
|
id: string;
|
||||||
|
name: CipherString;
|
||||||
|
|
||||||
|
constructor(obj?: FolderData, alreadyEncrypted: boolean = false) {
|
||||||
|
super();
|
||||||
|
if (obj == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.buildDomainModel(this, obj, {
|
||||||
|
id: null,
|
||||||
|
name: null,
|
||||||
|
}, alreadyEncrypted, ['id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypt(): Promise<any> {
|
||||||
|
const model = {
|
||||||
|
id: this.id,
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.decryptObj(model, {
|
||||||
|
name: null,
|
||||||
|
}, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Folder };
|
||||||
|
(window as any).Folder = Folder;
|
79
src/models/domain/identity.ts
Normal file
79
src/models/domain/identity.ts
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import { IdentityData } from '../data/identityData';
|
||||||
|
|
||||||
|
import { CipherString } from './cipherString';
|
||||||
|
import Domain from './domain';
|
||||||
|
|
||||||
|
class Identity extends Domain {
|
||||||
|
title: CipherString;
|
||||||
|
firstName: CipherString;
|
||||||
|
middleName: CipherString;
|
||||||
|
lastName: CipherString;
|
||||||
|
address1: CipherString;
|
||||||
|
address2: CipherString;
|
||||||
|
address3: CipherString;
|
||||||
|
city: CipherString;
|
||||||
|
state: CipherString;
|
||||||
|
postalCode: CipherString;
|
||||||
|
country: CipherString;
|
||||||
|
company: CipherString;
|
||||||
|
email: CipherString;
|
||||||
|
phone: CipherString;
|
||||||
|
ssn: CipherString;
|
||||||
|
username: CipherString;
|
||||||
|
passportNumber: CipherString;
|
||||||
|
licenseNumber: CipherString;
|
||||||
|
|
||||||
|
constructor(obj?: IdentityData, alreadyEncrypted: boolean = false) {
|
||||||
|
super();
|
||||||
|
if (obj == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.buildDomainModel(this, obj, {
|
||||||
|
title: null,
|
||||||
|
firstName: null,
|
||||||
|
middleName: null,
|
||||||
|
lastName: null,
|
||||||
|
address1: null,
|
||||||
|
address2: null,
|
||||||
|
address3: null,
|
||||||
|
city: null,
|
||||||
|
state: null,
|
||||||
|
postalCode: null,
|
||||||
|
country: null,
|
||||||
|
company: null,
|
||||||
|
email: null,
|
||||||
|
phone: null,
|
||||||
|
ssn: null,
|
||||||
|
username: null,
|
||||||
|
passportNumber: null,
|
||||||
|
licenseNumber: null,
|
||||||
|
}, alreadyEncrypted, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypt(orgId: string): Promise<any> {
|
||||||
|
return this.decryptObj({}, {
|
||||||
|
title: null,
|
||||||
|
firstName: null,
|
||||||
|
middleName: null,
|
||||||
|
lastName: null,
|
||||||
|
address1: null,
|
||||||
|
address2: null,
|
||||||
|
address3: null,
|
||||||
|
city: null,
|
||||||
|
state: null,
|
||||||
|
postalCode: null,
|
||||||
|
country: null,
|
||||||
|
company: null,
|
||||||
|
email: null,
|
||||||
|
phone: null,
|
||||||
|
ssn: null,
|
||||||
|
username: null,
|
||||||
|
passportNumber: null,
|
||||||
|
licenseNumber: null,
|
||||||
|
}, orgId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Identity };
|
||||||
|
(window as any).Identity = Identity;
|
37
src/models/domain/login.ts
Normal file
37
src/models/domain/login.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { LoginData } from '../data/loginData';
|
||||||
|
|
||||||
|
import { CipherString } from './cipherString';
|
||||||
|
import Domain from './domain';
|
||||||
|
|
||||||
|
class Login extends Domain {
|
||||||
|
uri: CipherString;
|
||||||
|
username: CipherString;
|
||||||
|
password: CipherString;
|
||||||
|
totp: CipherString;
|
||||||
|
|
||||||
|
constructor(obj?: LoginData, alreadyEncrypted: boolean = false) {
|
||||||
|
super();
|
||||||
|
if (obj == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.buildDomainModel(this, obj, {
|
||||||
|
uri: null,
|
||||||
|
username: null,
|
||||||
|
password: null,
|
||||||
|
totp: null,
|
||||||
|
}, alreadyEncrypted, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypt(orgId: string): Promise<any> {
|
||||||
|
return this.decryptObj({}, {
|
||||||
|
uri: null,
|
||||||
|
username: null,
|
||||||
|
password: null,
|
||||||
|
totp: null,
|
||||||
|
}, orgId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Login };
|
||||||
|
(window as any).Login = Login;
|
9
src/models/domain/passwordHistory.ts
Normal file
9
src/models/domain/passwordHistory.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export default class PasswordHistory {
|
||||||
|
password: string;
|
||||||
|
date: number;
|
||||||
|
|
||||||
|
constructor(password: string, date: number) {
|
||||||
|
this.password = password;
|
||||||
|
this.date = date;
|
||||||
|
}
|
||||||
|
}
|
27
src/models/domain/secureNote.ts
Normal file
27
src/models/domain/secureNote.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { SecureNoteType } from '../../enums/secureNoteType.enum';
|
||||||
|
|
||||||
|
import { SecureNoteData } from '../data/secureNoteData';
|
||||||
|
|
||||||
|
import Domain from './domain';
|
||||||
|
|
||||||
|
class SecureNote extends Domain {
|
||||||
|
type: SecureNoteType;
|
||||||
|
|
||||||
|
constructor(obj?: SecureNoteData, alreadyEncrypted: boolean = false) {
|
||||||
|
super();
|
||||||
|
if (obj == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.type = obj.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypt(orgId: string): any {
|
||||||
|
return {
|
||||||
|
type: this.type,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { SecureNote };
|
||||||
|
(window as any).SecureNote = SecureNote;
|
78
src/models/domain/symmetricCryptoKey.ts
Normal file
78
src/models/domain/symmetricCryptoKey.ts
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import { EncryptionType } from '../../enums/encryptionType.enum';
|
||||||
|
|
||||||
|
import SymmetricCryptoKeyBuffers from './symmetricCryptoKeyBuffers';
|
||||||
|
|
||||||
|
import UtilsService from '../../services/utils.service';
|
||||||
|
|
||||||
|
export default class SymmetricCryptoKey {
|
||||||
|
key: string;
|
||||||
|
keyB64: string;
|
||||||
|
encKey: string;
|
||||||
|
macKey: string;
|
||||||
|
encType: EncryptionType;
|
||||||
|
keyBuf: SymmetricCryptoKeyBuffers;
|
||||||
|
|
||||||
|
constructor(keyBytes: string, b64KeyBytes?: boolean, encType?: EncryptionType) {
|
||||||
|
if (b64KeyBytes) {
|
||||||
|
keyBytes = forge.util.decode64(keyBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!keyBytes) {
|
||||||
|
throw new Error('Must provide keyBytes');
|
||||||
|
}
|
||||||
|
|
||||||
|
const buffer = forge.util.createBuffer(keyBytes);
|
||||||
|
if (!buffer || buffer.length() === 0) {
|
||||||
|
throw new Error('Couldn\'t make buffer');
|
||||||
|
}
|
||||||
|
|
||||||
|
const bufferLength: number = buffer.length();
|
||||||
|
|
||||||
|
if (encType == null) {
|
||||||
|
if (bufferLength === 32) {
|
||||||
|
encType = EncryptionType.AesCbc256_B64;
|
||||||
|
} else if (bufferLength === 64) {
|
||||||
|
encType = EncryptionType.AesCbc256_HmacSha256_B64;
|
||||||
|
} else {
|
||||||
|
throw new Error('Unable to determine encType.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.key = keyBytes;
|
||||||
|
this.keyB64 = forge.util.encode64(keyBytes);
|
||||||
|
this.encType = encType;
|
||||||
|
|
||||||
|
if (encType === EncryptionType.AesCbc256_B64 && bufferLength === 32) {
|
||||||
|
this.encKey = keyBytes;
|
||||||
|
this.macKey = null;
|
||||||
|
} else if (encType === EncryptionType.AesCbc128_HmacSha256_B64 && bufferLength === 32) {
|
||||||
|
this.encKey = buffer.getBytes(16); // first half
|
||||||
|
this.macKey = buffer.getBytes(16); // second half
|
||||||
|
} else if (encType === EncryptionType.AesCbc256_HmacSha256_B64 && bufferLength === 64) {
|
||||||
|
this.encKey = buffer.getBytes(32); // first half
|
||||||
|
this.macKey = buffer.getBytes(32); // second half
|
||||||
|
} else {
|
||||||
|
throw new Error('Unsupported encType/key length.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getBuffers() {
|
||||||
|
if (this.keyBuf) {
|
||||||
|
return this.keyBuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
const key = UtilsService.fromB64ToArray(this.keyB64);
|
||||||
|
const keys = new SymmetricCryptoKeyBuffers(key.buffer);
|
||||||
|
|
||||||
|
if (this.macKey) {
|
||||||
|
keys.encKey = key.slice(0, key.length / 2).buffer;
|
||||||
|
keys.macKey = key.slice(key.length / 2).buffer;
|
||||||
|
} else {
|
||||||
|
keys.encKey = key.buffer;
|
||||||
|
keys.macKey = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.keyBuf = keys;
|
||||||
|
return this.keyBuf;
|
||||||
|
}
|
||||||
|
}
|
9
src/models/domain/symmetricCryptoKeyBuffers.ts
Normal file
9
src/models/domain/symmetricCryptoKeyBuffers.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export default class SymmetricCryptoKeyBuffers {
|
||||||
|
key: ArrayBuffer;
|
||||||
|
encKey?: ArrayBuffer;
|
||||||
|
macKey?: ArrayBuffer;
|
||||||
|
|
||||||
|
constructor(key: ArrayBuffer) {
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
}
|
@ -1,468 +0,0 @@
|
|||||||
var CipherString = function () {
|
|
||||||
this.encryptedString = null;
|
|
||||||
this.encryptionType = null;
|
|
||||||
this.decryptedValue = null;
|
|
||||||
this.cipherText = null;
|
|
||||||
this.initializationVector = null;
|
|
||||||
this.mac = null;
|
|
||||||
this.cryptoService = chrome.extension.getBackgroundPage().bg_cryptoService;
|
|
||||||
|
|
||||||
var constants = chrome.extension.getBackgroundPage().bg_constantsService;
|
|
||||||
|
|
||||||
if (arguments.length >= 2) {
|
|
||||||
// ct and header
|
|
||||||
this.encryptedString = arguments[0] + '.' + arguments[1];
|
|
||||||
|
|
||||||
// iv
|
|
||||||
if (arguments.length > 2 && arguments[2]) {
|
|
||||||
this.encryptedString += ('|' + arguments[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// mac
|
|
||||||
if (arguments.length > 3 && arguments[3]) {
|
|
||||||
this.encryptedString += ('|' + arguments[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.encryptionType = arguments[0];
|
|
||||||
this.cipherText = arguments[1];
|
|
||||||
this.initializationVector = arguments[2] || null;
|
|
||||||
this.mac = arguments[3] || null;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (arguments.length !== 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.encryptedString = arguments[0];
|
|
||||||
if (!this.encryptedString) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var headerPieces = this.encryptedString.split('.'),
|
|
||||||
encPieces;
|
|
||||||
|
|
||||||
if (headerPieces.length === 2) {
|
|
||||||
try {
|
|
||||||
this.encryptionType = parseInt(headerPieces[0]);
|
|
||||||
encPieces = headerPieces[1].split('|');
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
encPieces = this.encryptedString.split('|');
|
|
||||||
this.encryptionType = encPieces.length === 3 ? constants.encType.AesCbc128_HmacSha256_B64 :
|
|
||||||
constants.encType.AesCbc256_B64;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (this.encryptionType) {
|
|
||||||
case constants.encType.AesCbc128_HmacSha256_B64:
|
|
||||||
case constants.encType.AesCbc256_HmacSha256_B64:
|
|
||||||
if (encPieces.length !== 3) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.initializationVector = encPieces[0];
|
|
||||||
this.cipherText = encPieces[1];
|
|
||||||
this.mac = encPieces[2];
|
|
||||||
break;
|
|
||||||
case constants.encType.AesCbc256_B64:
|
|
||||||
if (encPieces.length !== 2) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.initializationVector = encPieces[0];
|
|
||||||
this.cipherText = encPieces[1];
|
|
||||||
break;
|
|
||||||
case constants.encType.Rsa2048_OaepSha256_B64:
|
|
||||||
case constants.encType.Rsa2048_OaepSha1_B64:
|
|
||||||
if (encPieces.length !== 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.cipherText = encPieces[0];
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var Cipher = function (obj, alreadyEncrypted, localData) {
|
|
||||||
this.constantsService = chrome.extension.getBackgroundPage().bg_constantsService;
|
|
||||||
this.utilsService = chrome.extension.getBackgroundPage().bg_utilsService;
|
|
||||||
|
|
||||||
buildDomainModel(this, obj, {
|
|
||||||
id: null,
|
|
||||||
organizationId: null,
|
|
||||||
folderId: null,
|
|
||||||
name: null,
|
|
||||||
notes: null
|
|
||||||
}, alreadyEncrypted, ['id', 'organizationId', 'folderId']);
|
|
||||||
|
|
||||||
this.type = obj.type;
|
|
||||||
this.favorite = obj.favorite ? true : false;
|
|
||||||
this.organizationUseTotp = obj.organizationUseTotp ? true : false;
|
|
||||||
this.edit = obj.edit ? true : false;
|
|
||||||
this.localData = localData;
|
|
||||||
|
|
||||||
switch (this.type) {
|
|
||||||
case this.constantsService.cipherType.login:
|
|
||||||
this.login = new Login2(obj.login, alreadyEncrypted);
|
|
||||||
break;
|
|
||||||
case this.constantsService.cipherType.secureNote:
|
|
||||||
this.secureNote = new SecureNote(obj.secureNote, alreadyEncrypted);
|
|
||||||
break;
|
|
||||||
case this.constantsService.cipherType.card:
|
|
||||||
this.card = new Card(obj.card, alreadyEncrypted);
|
|
||||||
break;
|
|
||||||
case this.constantsService.cipherType.identity:
|
|
||||||
this.identity = new Identity(obj.identity, alreadyEncrypted);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
var i;
|
|
||||||
if (obj.attachments) {
|
|
||||||
this.attachments = [];
|
|
||||||
for (i = 0; i < obj.attachments.length; i++) {
|
|
||||||
this.attachments.push(new Attachment(obj.attachments[i], alreadyEncrypted));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.attachments = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj.fields) {
|
|
||||||
this.fields = [];
|
|
||||||
for (i = 0; i < obj.fields.length; i++) {
|
|
||||||
this.fields.push(new Field(obj.fields[i], alreadyEncrypted));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.fields = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var Login2 = function (obj, alreadyEncrypted) {
|
|
||||||
buildDomainModel(this, obj, {
|
|
||||||
uri: null,
|
|
||||||
username: null,
|
|
||||||
password: null,
|
|
||||||
totp: null
|
|
||||||
}, alreadyEncrypted, []);
|
|
||||||
};
|
|
||||||
|
|
||||||
var Identity = function (obj, alreadyEncrypted) {
|
|
||||||
buildDomainModel(this, obj, {
|
|
||||||
title: null,
|
|
||||||
firstName: null,
|
|
||||||
middleName: null,
|
|
||||||
lastName: null,
|
|
||||||
address1: null,
|
|
||||||
address2: null,
|
|
||||||
address3: null,
|
|
||||||
city: null,
|
|
||||||
state: null,
|
|
||||||
postalCode: null,
|
|
||||||
country: null,
|
|
||||||
company: null,
|
|
||||||
email: null,
|
|
||||||
phone: null,
|
|
||||||
ssn: null,
|
|
||||||
username: null,
|
|
||||||
passportNumber: null,
|
|
||||||
licenseNumber: null
|
|
||||||
}, alreadyEncrypted, []);
|
|
||||||
};
|
|
||||||
|
|
||||||
var Card = function (obj, alreadyEncrypted) {
|
|
||||||
buildDomainModel(this, obj, {
|
|
||||||
cardholderName: null,
|
|
||||||
brand: null,
|
|
||||||
number: null,
|
|
||||||
expMonth: null,
|
|
||||||
expYear: null,
|
|
||||||
code: null
|
|
||||||
}, alreadyEncrypted, []);
|
|
||||||
};
|
|
||||||
|
|
||||||
var SecureNote = function (obj, alreadyEncrypted) {
|
|
||||||
this.type = obj.type;
|
|
||||||
};
|
|
||||||
|
|
||||||
var Field = function (obj, alreadyEncrypted) {
|
|
||||||
this.type = obj.type;
|
|
||||||
buildDomainModel(this, obj, {
|
|
||||||
name: null,
|
|
||||||
value: null
|
|
||||||
}, alreadyEncrypted, []);
|
|
||||||
};
|
|
||||||
|
|
||||||
var Attachment = function (obj, alreadyEncrypted) {
|
|
||||||
this.size = obj.size;
|
|
||||||
buildDomainModel(this, obj, {
|
|
||||||
id: null,
|
|
||||||
url: null,
|
|
||||||
sizeName: null,
|
|
||||||
fileName: null
|
|
||||||
}, alreadyEncrypted, ['id', 'url', 'sizeName']);
|
|
||||||
};
|
|
||||||
|
|
||||||
var Folder = function (obj, alreadyEncrypted) {
|
|
||||||
buildDomainModel(this, obj, {
|
|
||||||
id: null,
|
|
||||||
name: null
|
|
||||||
}, alreadyEncrypted, ['id']);
|
|
||||||
};
|
|
||||||
|
|
||||||
function buildDomainModel(model, obj, map, alreadyEncrypted, notEncList) {
|
|
||||||
notEncList = notEncList || [];
|
|
||||||
for (var prop in map) {
|
|
||||||
if (map.hasOwnProperty(prop)) {
|
|
||||||
var objProp = obj[(map[prop] || prop)];
|
|
||||||
if (alreadyEncrypted === true || notEncList.indexOf(prop) > -1) {
|
|
||||||
model[prop] = objProp ? objProp : null;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
model[prop] = objProp ? new CipherString(objProp) : null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(function () {
|
|
||||||
CipherString.prototype.decrypt = function (orgId) {
|
|
||||||
if (this.decryptedValue) {
|
|
||||||
return Q(this.decryptedValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
var self = this;
|
|
||||||
return self.cryptoService.getOrgKey(orgId).then(function (orgKey) {
|
|
||||||
return self.cryptoService.decrypt(self, orgKey);
|
|
||||||
}).then(function (decValue) {
|
|
||||||
self.decryptedValue = decValue;
|
|
||||||
return self.decryptedValue;
|
|
||||||
}).catch(function () {
|
|
||||||
self.decryptedValue = '[error: cannot decrypt]';
|
|
||||||
return self.decryptedValue;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Cipher.prototype.decrypt = function () {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
var model = {
|
|
||||||
id: self.id,
|
|
||||||
organizationId: self.organizationId,
|
|
||||||
folderId: self.folderId,
|
|
||||||
favorite: self.favorite,
|
|
||||||
type: self.type,
|
|
||||||
localData: self.localData
|
|
||||||
};
|
|
||||||
|
|
||||||
var attachments = [];
|
|
||||||
var fields = [];
|
|
||||||
|
|
||||||
return decryptObj(model, this, {
|
|
||||||
name: null,
|
|
||||||
notes: null
|
|
||||||
}, self.organizationId).then(function () {
|
|
||||||
switch (self.type) {
|
|
||||||
case self.constantsService.cipherType.login:
|
|
||||||
return self.login.decrypt(self.organizationId);
|
|
||||||
case self.constantsService.cipherType.secureNote:
|
|
||||||
return self.secureNote.decrypt(self.organizationId);
|
|
||||||
case self.constantsService.cipherType.card:
|
|
||||||
return self.card.decrypt(self.organizationId);
|
|
||||||
case self.constantsService.cipherType.identity:
|
|
||||||
return self.identity.decrypt(self.organizationId);
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}).then(function (decObj) {
|
|
||||||
switch (self.type) {
|
|
||||||
case self.constantsService.cipherType.login:
|
|
||||||
model.login = decObj;
|
|
||||||
model.subTitle = model.login.username;
|
|
||||||
if (model.login.uri) {
|
|
||||||
model.login.domain = self.utilsService.getDomain(model.login.uri);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case self.constantsService.cipherType.secureNote:
|
|
||||||
model.secureNote = decObj;
|
|
||||||
model.subTitle = null;
|
|
||||||
break;
|
|
||||||
case self.constantsService.cipherType.card:
|
|
||||||
model.card = decObj;
|
|
||||||
model.subTitle = model.card.brand;
|
|
||||||
if (model.card.number && model.card.number.length >= 4) {
|
|
||||||
if (model.subTitle !== '') {
|
|
||||||
model.subTitle += ', ';
|
|
||||||
}
|
|
||||||
model.subTitle += ('*' + model.card.number.substr(model.card.number.length - 4));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case self.constantsService.cipherType.identity:
|
|
||||||
model.identity = decObj;
|
|
||||||
model.subTitle = '';
|
|
||||||
if (model.identity.firstName) {
|
|
||||||
model.subTitle = model.identity.firstName;
|
|
||||||
}
|
|
||||||
if (model.identity.lastName) {
|
|
||||||
if (model.subTitle !== '') {
|
|
||||||
model.subTitle += ' ';
|
|
||||||
}
|
|
||||||
model.subTitle += model.identity.lastName;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}).then(function () {
|
|
||||||
if (self.attachments) {
|
|
||||||
return self.attachments.reduce(function (promise, attachment) {
|
|
||||||
return promise.then(function () {
|
|
||||||
return attachment.decrypt(self.organizationId);
|
|
||||||
}).then(function (decAttachment) {
|
|
||||||
attachments.push(decAttachment);
|
|
||||||
});
|
|
||||||
}, Q());
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}).then(function () {
|
|
||||||
model.attachments = attachments.length ? attachments : null;
|
|
||||||
|
|
||||||
if (self.fields) {
|
|
||||||
return self.fields.reduce(function (promise, field) {
|
|
||||||
return promise.then(function () {
|
|
||||||
return field.decrypt(self.organizationId);
|
|
||||||
}).then(function (decField) {
|
|
||||||
fields.push(decField);
|
|
||||||
});
|
|
||||||
}, Q());
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}).then(function () {
|
|
||||||
model.fields = fields.length ? fields : null;
|
|
||||||
return model;
|
|
||||||
}, function (e) {
|
|
||||||
console.log(e);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Login2.prototype.decrypt = function (orgId) {
|
|
||||||
return decryptObj({}, this, {
|
|
||||||
uri: null,
|
|
||||||
username: null,
|
|
||||||
password: null,
|
|
||||||
totp: null
|
|
||||||
}, orgId);
|
|
||||||
};
|
|
||||||
|
|
||||||
Card.prototype.decrypt = function (orgId) {
|
|
||||||
return decryptObj({}, this, {
|
|
||||||
cardholderName: null,
|
|
||||||
brand: null,
|
|
||||||
number: null,
|
|
||||||
expMonth: null,
|
|
||||||
expYear: null,
|
|
||||||
code: null
|
|
||||||
}, orgId);
|
|
||||||
};
|
|
||||||
|
|
||||||
SecureNote.prototype.decrypt = function (orgId) {
|
|
||||||
return {
|
|
||||||
type: this.type
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
Identity.prototype.decrypt = function (orgId) {
|
|
||||||
return decryptObj({}, this, {
|
|
||||||
title: null,
|
|
||||||
firstName: null,
|
|
||||||
middleName: null,
|
|
||||||
lastName: null,
|
|
||||||
address1: null,
|
|
||||||
address2: null,
|
|
||||||
address3: null,
|
|
||||||
city: null,
|
|
||||||
state: null,
|
|
||||||
postalCode: null,
|
|
||||||
country: null,
|
|
||||||
company: null,
|
|
||||||
email: null,
|
|
||||||
phone: null,
|
|
||||||
ssn: null,
|
|
||||||
username: null,
|
|
||||||
passportNumber: null,
|
|
||||||
licenseNumber: null
|
|
||||||
}, orgId);
|
|
||||||
};
|
|
||||||
|
|
||||||
Field.prototype.decrypt = function (orgId) {
|
|
||||||
var model = {
|
|
||||||
type: this.type
|
|
||||||
};
|
|
||||||
|
|
||||||
return decryptObj(model, this, {
|
|
||||||
name: null,
|
|
||||||
value: null
|
|
||||||
}, orgId);
|
|
||||||
};
|
|
||||||
|
|
||||||
Attachment.prototype.decrypt = function (orgId) {
|
|
||||||
var model = {
|
|
||||||
id: this.id,
|
|
||||||
size: this.size,
|
|
||||||
sizeName: this.sizeName,
|
|
||||||
url: this.url
|
|
||||||
};
|
|
||||||
|
|
||||||
return decryptObj(model, this, {
|
|
||||||
fileName: null
|
|
||||||
}, orgId);
|
|
||||||
};
|
|
||||||
|
|
||||||
Folder.prototype.decrypt = function () {
|
|
||||||
var self = this;
|
|
||||||
var model = {
|
|
||||||
id: self.id
|
|
||||||
};
|
|
||||||
|
|
||||||
return decryptObj(model, this, {
|
|
||||||
name: null
|
|
||||||
}, null);
|
|
||||||
};
|
|
||||||
|
|
||||||
function decryptObj(model, self, map, orgId) {
|
|
||||||
var promises = [];
|
|
||||||
for (var prop in map) {
|
|
||||||
if (map.hasOwnProperty(prop)) {
|
|
||||||
/* jshint ignore:start */
|
|
||||||
(function (theProp) {
|
|
||||||
var promise = Q().then(function () {
|
|
||||||
var mapProp = map[theProp] || theProp;
|
|
||||||
if (self[mapProp]) {
|
|
||||||
return self[mapProp].decrypt(orgId);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}).then(function (val) {
|
|
||||||
model[theProp] = val;
|
|
||||||
return;
|
|
||||||
});
|
|
||||||
|
|
||||||
promises.push(promise);
|
|
||||||
})(prop);
|
|
||||||
/* jshint ignore:end */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Q.all(promises).then(function () {
|
|
||||||
return model;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})();
|
|
89
src/models/request/cipherRequest.ts
Normal file
89
src/models/request/cipherRequest.ts
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
import { CipherType } from '../../enums/cipherType.enum';
|
||||||
|
|
||||||
|
class CipherRequest {
|
||||||
|
type: CipherType;
|
||||||
|
folderId: string;
|
||||||
|
organizationId: string;
|
||||||
|
name: string;
|
||||||
|
notes: string;
|
||||||
|
favorite: boolean;
|
||||||
|
login: any;
|
||||||
|
secureNote: any;
|
||||||
|
card: any;
|
||||||
|
identity: any;
|
||||||
|
fields: any[];
|
||||||
|
|
||||||
|
constructor(cipher: any) {
|
||||||
|
this.type = cipher.type;
|
||||||
|
this.folderId = cipher.folderId;
|
||||||
|
this.organizationId = cipher.organizationId;
|
||||||
|
this.name = cipher.name ? cipher.name.encryptedString : null;
|
||||||
|
this.notes = cipher.notes ? cipher.notes.encryptedString : null;
|
||||||
|
this.favorite = cipher.favorite;
|
||||||
|
|
||||||
|
switch (this.type) {
|
||||||
|
case CipherType.Login:
|
||||||
|
this.login = {
|
||||||
|
uri: cipher.login.uri ? cipher.login.uri.encryptedString : null,
|
||||||
|
username: cipher.login.username ? cipher.login.username.encryptedString : null,
|
||||||
|
password: cipher.login.password ? cipher.login.password.encryptedString : null,
|
||||||
|
totp: cipher.login.totp ? cipher.login.totp.encryptedString : null,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case CipherType.SecureNote:
|
||||||
|
this.secureNote = {
|
||||||
|
type: cipher.secureNote.type,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case CipherType.Card:
|
||||||
|
this.card = {
|
||||||
|
cardholderName: cipher.card.cardholderName ? cipher.card.cardholderName.encryptedString : null,
|
||||||
|
brand: cipher.card.brand ? cipher.card.brand.encryptedString : null,
|
||||||
|
number: cipher.card.number ? cipher.card.number.encryptedString : null,
|
||||||
|
expMonth: cipher.card.expMonth ? cipher.card.expMonth.encryptedString : null,
|
||||||
|
expYear: cipher.card.expYear ? cipher.card.expYear.encryptedString : null,
|
||||||
|
code: cipher.card.code ? cipher.card.code.encryptedString : null,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case CipherType.Identity:
|
||||||
|
this.identity = {
|
||||||
|
title: cipher.identity.title ? cipher.identity.title.encryptedString : null,
|
||||||
|
firstName: cipher.identity.firstName ? cipher.identity.firstName.encryptedString : null,
|
||||||
|
middleName: cipher.identity.middleName ? cipher.identity.middleName.encryptedString : null,
|
||||||
|
lastName: cipher.identity.lastName ? cipher.identity.lastName.encryptedString : null,
|
||||||
|
address1: cipher.identity.address1 ? cipher.identity.address1.encryptedString : null,
|
||||||
|
address2: cipher.identity.address2 ? cipher.identity.address2.encryptedString : null,
|
||||||
|
address3: cipher.identity.address3 ? cipher.identity.address3.encryptedString : null,
|
||||||
|
city: cipher.identity.city ? cipher.identity.city.encryptedString : null,
|
||||||
|
state: cipher.identity.state ? cipher.identity.state.encryptedString : null,
|
||||||
|
postalCode: cipher.identity.postalCode ? cipher.identity.postalCode.encryptedString : null,
|
||||||
|
country: cipher.identity.country ? cipher.identity.country.encryptedString : null,
|
||||||
|
company: cipher.identity.company ? cipher.identity.company.encryptedString : null,
|
||||||
|
email: cipher.identity.email ? cipher.identity.email.encryptedString : null,
|
||||||
|
phone: cipher.identity.phone ? cipher.identity.phone.encryptedString : null,
|
||||||
|
ssn: cipher.identity.ssn ? cipher.identity.ssn.encryptedString : null,
|
||||||
|
username: cipher.identity.username ? cipher.identity.username.encryptedString : null,
|
||||||
|
passportNumber: cipher.identity.passportNumber ?
|
||||||
|
cipher.identity.passportNumber.encryptedString : null,
|
||||||
|
licenseNumber: cipher.identity.licenseNumber ? cipher.identity.licenseNumber.encryptedString : null,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cipher.fields) {
|
||||||
|
this.fields = [];
|
||||||
|
for (const field of cipher.fields) {
|
||||||
|
this.fields.push({
|
||||||
|
type: field.type,
|
||||||
|
name: field.name ? field.name.encryptedString : null,
|
||||||
|
value: field.value ? field.value.encryptedString : null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { CipherRequest };
|
||||||
|
(window as any).CipherRequest = CipherRequest;
|
16
src/models/request/deviceRequest.ts
Normal file
16
src/models/request/deviceRequest.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
class DeviceRequest {
|
||||||
|
type: number; // TODO: enum
|
||||||
|
name: string;
|
||||||
|
identifier: string;
|
||||||
|
pushToken?: string;
|
||||||
|
|
||||||
|
constructor(appId: string, utilsService: any) { // TODO: utils service type
|
||||||
|
this.type = utilsService.getDeviceType();
|
||||||
|
this.name = utilsService.getBrowser();
|
||||||
|
this.identifier = appId;
|
||||||
|
this.pushToken = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { DeviceRequest };
|
||||||
|
(window as any).DeviceRequest = DeviceRequest;
|
10
src/models/request/deviceTokenRequest.ts
Normal file
10
src/models/request/deviceTokenRequest.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
class DeviceTokenRequest {
|
||||||
|
pushToken: string;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.pushToken = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { DeviceTokenRequest };
|
||||||
|
(window as any).DeviceTokenRequest = DeviceTokenRequest;
|
10
src/models/request/folderRequest.ts
Normal file
10
src/models/request/folderRequest.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
class FolderRequest {
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
constructor(folder: any) { // TODO: folder type
|
||||||
|
this.name = folder.name ? folder.name.encryptedString : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { FolderRequest };
|
||||||
|
(window as any).FolderRequest = FolderRequest;
|
10
src/models/request/passwordHintRequest.ts
Normal file
10
src/models/request/passwordHintRequest.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
class PasswordHintRequest {
|
||||||
|
email: string;
|
||||||
|
|
||||||
|
constructor(email: string) {
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { PasswordHintRequest };
|
||||||
|
(window as any).PasswordHintRequest = PasswordHintRequest;
|
18
src/models/request/registerRequest.ts
Normal file
18
src/models/request/registerRequest.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
class RegisterRequest {
|
||||||
|
name: string;
|
||||||
|
email: string;
|
||||||
|
masterPasswordHash: string;
|
||||||
|
masterPasswordHint: string;
|
||||||
|
key: string;
|
||||||
|
|
||||||
|
constructor(email: string, masterPasswordHash: string, masterPasswordHint: string, key: string) {
|
||||||
|
this.name = null;
|
||||||
|
this.email = email;
|
||||||
|
this.masterPasswordHash = masterPasswordHash;
|
||||||
|
this.masterPasswordHint = masterPasswordHint ? masterPasswordHint : null;
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { RegisterRequest };
|
||||||
|
(window as any).RegisterRequest = RegisterRequest;
|
46
src/models/request/tokenRequest.ts
Normal file
46
src/models/request/tokenRequest.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
class TokenRequest {
|
||||||
|
email: string;
|
||||||
|
masterPasswordHash: string;
|
||||||
|
token: string;
|
||||||
|
provider: number;
|
||||||
|
remember: boolean;
|
||||||
|
device?: any;
|
||||||
|
|
||||||
|
constructor(email: string, masterPasswordHash: string, provider: number,
|
||||||
|
token: string, remember: boolean, device?: any) {
|
||||||
|
this.email = email;
|
||||||
|
this.masterPasswordHash = masterPasswordHash;
|
||||||
|
this.token = token;
|
||||||
|
this.provider = provider;
|
||||||
|
this.remember = remember;
|
||||||
|
this.device = device ? device : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
toIdentityToken() {
|
||||||
|
const obj: any = {
|
||||||
|
grant_type: 'password',
|
||||||
|
username: this.email,
|
||||||
|
password: this.masterPasswordHash,
|
||||||
|
scope: 'api offline_access',
|
||||||
|
client_id: 'browser',
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.device) {
|
||||||
|
obj.deviceType = this.device.type;
|
||||||
|
obj.deviceIdentifier = this.device.identifier;
|
||||||
|
obj.deviceName = this.device.name;
|
||||||
|
obj.devicePushToken = this.device.pushToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.token && this.provider !== null && (typeof this.provider !== 'undefined')) {
|
||||||
|
obj.twoFactorToken = this.token;
|
||||||
|
obj.twoFactorProvider = this.provider;
|
||||||
|
obj.twoFactorRemember = this.remember ? '1' : '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { TokenRequest };
|
||||||
|
(window as any).TokenRequest = TokenRequest;
|
12
src/models/request/twoFactorEmailRequest.ts
Normal file
12
src/models/request/twoFactorEmailRequest.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
class TwoFactorEmailRequest {
|
||||||
|
email: string;
|
||||||
|
masterPasswordHash: string;
|
||||||
|
|
||||||
|
constructor(email: string, masterPasswordHash: string) {
|
||||||
|
this.email = email;
|
||||||
|
this.masterPasswordHash = masterPasswordHash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { TwoFactorEmailRequest };
|
||||||
|
(window as any).TwoFactorEmailRequest = TwoFactorEmailRequest;
|
18
src/models/response/attachmentResponse.ts
Normal file
18
src/models/response/attachmentResponse.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
class AttachmentResponse {
|
||||||
|
id: string;
|
||||||
|
url: string;
|
||||||
|
fileName: string;
|
||||||
|
size: number;
|
||||||
|
sizeName: string;
|
||||||
|
|
||||||
|
constructor(response: any) {
|
||||||
|
this.id = response.Id;
|
||||||
|
this.url = response.Url;
|
||||||
|
this.fileName = response.FileName;
|
||||||
|
this.size = response.Size;
|
||||||
|
this.sizeName = response.SizeName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { AttachmentResponse };
|
||||||
|
(window as any).AttachmentResponse = AttachmentResponse;
|
36
src/models/response/cipherResponse.ts
Normal file
36
src/models/response/cipherResponse.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { AttachmentResponse } from './attachmentResponse';
|
||||||
|
|
||||||
|
class CipherResponse {
|
||||||
|
id: string;
|
||||||
|
organizationId: string;
|
||||||
|
folderId: string;
|
||||||
|
type: number;
|
||||||
|
favorite: boolean;
|
||||||
|
edit: boolean;
|
||||||
|
organizationUseTotp: boolean;
|
||||||
|
data: any;
|
||||||
|
revisionDate: string;
|
||||||
|
attachments: AttachmentResponse[];
|
||||||
|
|
||||||
|
constructor(response: any) {
|
||||||
|
this.id = response.Id;
|
||||||
|
this.organizationId = response.OrganizationId;
|
||||||
|
this.folderId = response.FolderId;
|
||||||
|
this.type = response.Type;
|
||||||
|
this.favorite = response.Favorite;
|
||||||
|
this.edit = response.Edit;
|
||||||
|
this.organizationUseTotp = response.OrganizationUseTotp;
|
||||||
|
this.data = response.Data;
|
||||||
|
this.revisionDate = response.RevisionDate;
|
||||||
|
|
||||||
|
if (response.Attachments != null) {
|
||||||
|
this.attachments = [];
|
||||||
|
for (const attachment of response.Attachments) {
|
||||||
|
this.attachments.push(new AttachmentResponse(attachment));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { CipherResponse };
|
||||||
|
(window as any).CipherResponse = CipherResponse;
|
18
src/models/response/deviceResponse.ts
Normal file
18
src/models/response/deviceResponse.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
class DeviceResponse {
|
||||||
|
id: string;
|
||||||
|
name: number;
|
||||||
|
identifier: string;
|
||||||
|
type: number; // TODO: Convert to enum
|
||||||
|
creationDate: string;
|
||||||
|
|
||||||
|
constructor(response: any) {
|
||||||
|
this.id = response.Id;
|
||||||
|
this.name = response.Name;
|
||||||
|
this.identifier = response.Identifier;
|
||||||
|
this.type = response.Type;
|
||||||
|
this.creationDate = response.CreationDate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { DeviceResponse };
|
||||||
|
(window as any).DeviceResponse = DeviceResponse;
|
20
src/models/response/domainsResponse.ts
Normal file
20
src/models/response/domainsResponse.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { GlobalDomainResponse } from './globalDomainResponse';
|
||||||
|
|
||||||
|
class DomainsResponse {
|
||||||
|
equivalentDomains: string[][];
|
||||||
|
globalEquivalentDomains: GlobalDomainResponse[] = [];
|
||||||
|
|
||||||
|
constructor(response: any) {
|
||||||
|
this.equivalentDomains = response.EquivalentDomains;
|
||||||
|
|
||||||
|
this.globalEquivalentDomains = [];
|
||||||
|
if (response.GlobalEquivalentDomains) {
|
||||||
|
for (const domain of response.GlobalEquivalentDomains) {
|
||||||
|
this.globalEquivalentDomains.push(new GlobalDomainResponse(domain));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { DomainsResponse };
|
||||||
|
(window as any).DomainsResponse = DomainsResponse;
|
25
src/models/response/errorResponse.ts
Normal file
25
src/models/response/errorResponse.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
class ErrorResponse {
|
||||||
|
message: string;
|
||||||
|
validationErrors: { [key: string]: string[]; };
|
||||||
|
statusCode: number;
|
||||||
|
|
||||||
|
constructor(response: any, status: number, identityResponse?: boolean) {
|
||||||
|
let errorModel = null;
|
||||||
|
if (identityResponse && response && response.ErrorModel) {
|
||||||
|
errorModel = response.ErrorModel;
|
||||||
|
} else if (response) {
|
||||||
|
errorModel = response;
|
||||||
|
//} else if (response.responseText && response.responseText.indexOf('{') === 0) {
|
||||||
|
// errorModel = JSON.parse(response.responseText);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errorModel) {
|
||||||
|
this.message = errorModel.Message;
|
||||||
|
this.validationErrors = errorModel.ValidationErrors;
|
||||||
|
}
|
||||||
|
this.statusCode = status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { ErrorResponse };
|
||||||
|
(window as any).ErrorResponse = ErrorResponse;
|
14
src/models/response/folderResponse.ts
Normal file
14
src/models/response/folderResponse.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
class FolderResponse {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
revisionDate: string;
|
||||||
|
|
||||||
|
constructor(response: any) {
|
||||||
|
this.id = response.Id;
|
||||||
|
this.name = response.Name;
|
||||||
|
this.revisionDate = response.RevisionDate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { FolderResponse };
|
||||||
|
(window as any).FolderResponse = FolderResponse;
|
14
src/models/response/globalDomainResponse.ts
Normal file
14
src/models/response/globalDomainResponse.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
class GlobalDomainResponse {
|
||||||
|
type: number;
|
||||||
|
domains: string[];
|
||||||
|
excluded: number[];
|
||||||
|
|
||||||
|
constructor(response: any) {
|
||||||
|
this.type = response.Type;
|
||||||
|
this.domains = response.Domains;
|
||||||
|
this.excluded = response.Excluded;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { GlobalDomainResponse };
|
||||||
|
(window as any).GlobalDomainResponse = GlobalDomainResponse;
|
24
src/models/response/identityTokenResponse.ts
Normal file
24
src/models/response/identityTokenResponse.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
class IdentityTokenResponse {
|
||||||
|
accessToken: string;
|
||||||
|
expiresIn: number;
|
||||||
|
refreshToken: string;
|
||||||
|
tokenType: string;
|
||||||
|
|
||||||
|
privateKey: string;
|
||||||
|
key: string;
|
||||||
|
twoFactorToken: string;
|
||||||
|
|
||||||
|
constructor(response: any) {
|
||||||
|
this.accessToken = response.access_token;
|
||||||
|
this.expiresIn = response.expires_in;
|
||||||
|
this.refreshToken = response.refresh_token;
|
||||||
|
this.tokenType = response.token_type;
|
||||||
|
|
||||||
|
this.privateKey = response.PrivateKey;
|
||||||
|
this.key = response.Key;
|
||||||
|
this.twoFactorToken = response.TwoFactorToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { IdentityTokenResponse };
|
||||||
|
(window as any).IdentityTokenResponse = IdentityTokenResponse;
|
12
src/models/response/keysResponse.ts
Normal file
12
src/models/response/keysResponse.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
class KeysResponse {
|
||||||
|
privateKey: string;
|
||||||
|
publicKey: string;
|
||||||
|
|
||||||
|
constructor(response: any) {
|
||||||
|
this.privateKey = response.PrivateKey;
|
||||||
|
this.publicKey = response.PublicKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { KeysResponse };
|
||||||
|
(window as any).KeysResponse = KeysResponse;
|
10
src/models/response/listResponse.ts
Normal file
10
src/models/response/listResponse.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
class ListResponse {
|
||||||
|
data: any;
|
||||||
|
|
||||||
|
constructor(data: any) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { ListResponse };
|
||||||
|
(window as any).ListResponse = ListResponse;
|
30
src/models/response/profileOrganizationResponse.ts
Normal file
30
src/models/response/profileOrganizationResponse.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
class ProfileOrganizationResponse {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
useGroups: boolean;
|
||||||
|
useDirectory: boolean;
|
||||||
|
useTotp: boolean;
|
||||||
|
seats: number;
|
||||||
|
maxCollections: number;
|
||||||
|
maxStorageGb?: number;
|
||||||
|
key: string;
|
||||||
|
status: number; // TODO: map to enum
|
||||||
|
type: number; // TODO: map to enum
|
||||||
|
|
||||||
|
constructor(response: any) {
|
||||||
|
this.id = response.Id;
|
||||||
|
this.name = response.Name;
|
||||||
|
this.useGroups = response.UseGroups;
|
||||||
|
this.useDirectory = response.UseDirectory;
|
||||||
|
this.useTotp = response.UseTotp;
|
||||||
|
this.seats = response.Seats;
|
||||||
|
this.maxCollections = response.MaxCollections;
|
||||||
|
this.maxStorageGb = response.MaxStorageGb;
|
||||||
|
this.key = response.Key;
|
||||||
|
this.status = response.Status;
|
||||||
|
this.type = response.Type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { ProfileOrganizationResponse };
|
||||||
|
(window as any).ProfileOrganizationResponse = ProfileOrganizationResponse;
|
39
src/models/response/profileResponse.ts
Normal file
39
src/models/response/profileResponse.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { ProfileOrganizationResponse } from './profileOrganizationResponse';
|
||||||
|
|
||||||
|
class ProfileResponse {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
email: string;
|
||||||
|
emailVerified: boolean;
|
||||||
|
masterPasswordHint: string;
|
||||||
|
premium: boolean;
|
||||||
|
culture: string;
|
||||||
|
twoFactorEnabled: boolean;
|
||||||
|
key: string;
|
||||||
|
privateKey: string;
|
||||||
|
securityStamp: string;
|
||||||
|
organizations: ProfileOrganizationResponse[] = [];
|
||||||
|
|
||||||
|
constructor(response: any) {
|
||||||
|
this.id = response.Id;
|
||||||
|
this.name = response.Name;
|
||||||
|
this.email = response.Email;
|
||||||
|
this.emailVerified = response.EmailVerified;
|
||||||
|
this.masterPasswordHint = response.MasterPasswordHint;
|
||||||
|
this.premium = response.Premium;
|
||||||
|
this.culture = response.Culture;
|
||||||
|
this.twoFactorEnabled = response.TwoFactorEnabled;
|
||||||
|
this.key = response.Key;
|
||||||
|
this.privateKey = response.PrivateKey;
|
||||||
|
this.securityStamp = response.SecurityStamp;
|
||||||
|
|
||||||
|
if (response.Organizations) {
|
||||||
|
for (const org of response.Organizations) {
|
||||||
|
this.organizations.push(new ProfileOrganizationResponse(org));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { ProfileResponse };
|
||||||
|
(window as any).ProfileResponse = ProfileResponse;
|
36
src/models/response/syncResponse.ts
Normal file
36
src/models/response/syncResponse.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { CipherResponse } from './cipherResponse';
|
||||||
|
import { DomainsResponse } from './domainsResponse';
|
||||||
|
import { FolderResponse } from './folderResponse';
|
||||||
|
import { ProfileResponse } from './profileResponse';
|
||||||
|
|
||||||
|
class SyncResponse {
|
||||||
|
profile?: ProfileResponse;
|
||||||
|
folders: FolderResponse[] = [];
|
||||||
|
ciphers: CipherResponse[] = [];
|
||||||
|
domains?: DomainsResponse;
|
||||||
|
|
||||||
|
constructor(response: any) {
|
||||||
|
if (response.Profile) {
|
||||||
|
this.profile = new ProfileResponse(response.Profile);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.Folders) {
|
||||||
|
for (const folder of response.Folders) {
|
||||||
|
this.folders.push(new FolderResponse(folder));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.Ciphers) {
|
||||||
|
for (const cipher of response.Ciphers) {
|
||||||
|
this.ciphers.push(new CipherResponse(cipher));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.Domains) {
|
||||||
|
this.domains = new DomainsResponse(response.Domains);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { SyncResponse };
|
||||||
|
(window as any).SyncResponse = SyncResponse;
|
@ -3,7 +3,6 @@
|
|||||||
<head>
|
<head>
|
||||||
<title></title>
|
<title></title>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" type="text/css" href="bar.css" />
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<table class="outter-table" cellpadding="0" cellspacing="0">
|
<table class="outter-table" cellpadding="0" cellspacing="0">
|
||||||
@ -37,7 +36,5 @@
|
|||||||
</table>
|
</table>
|
||||||
<div id="template-alert"></div>
|
<div id="template-alert"></div>
|
||||||
</div>
|
</div>
|
||||||
<script src="../lib/jquery/jquery.js"></script>
|
|
||||||
<script src="bar.js"></script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,63 +1,71 @@
|
|||||||
$(function () {
|
require('./bar.less');
|
||||||
var content = document.getElementById('content'),
|
|
||||||
closeButton = $('#close-button');
|
|
||||||
|
|
||||||
// i18n
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
$('body').addClass('lang-' + chrome.i18n.getUILanguage());
|
// delay 50ms so that we get proper body dimensions
|
||||||
|
setTimeout(load, 50);
|
||||||
|
|
||||||
$('#logo-link').attr('title', chrome.i18n.getMessage('appName'));
|
function load() {
|
||||||
closeButton.attr('title', chrome.i18n.getMessage('close'));
|
var content = document.getElementById('content'),
|
||||||
|
closeButton = document.getElementById('close-button'),
|
||||||
|
body = document.querySelector('body'),
|
||||||
|
bodyRect = body.getBoundingClientRect();
|
||||||
|
|
||||||
if (window.innerWidth < 768) {
|
// i18n
|
||||||
$('#template-add .add-save').text(chrome.i18n.getMessage('yes'));
|
body.classList.add('lang-' + chrome.i18n.getUILanguage());
|
||||||
$('#template-add .never-save').text(chrome.i18n.getMessage('never'));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$('#template-add .add-save').text(chrome.i18n.getMessage('notificationAddSave'));
|
|
||||||
$('#template-add .never-save').text(chrome.i18n.getMessage('notificationNeverSave'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#template-add .add-text').text(chrome.i18n.getMessage('notificationAddDesc'));
|
document.getElementById('logo-link').title = chrome.i18n.getMessage('appName');
|
||||||
|
closeButton.title = chrome.i18n.getMessage('close');
|
||||||
|
|
||||||
if (getQueryVariable('add')) {
|
if (bodyRect.width < 768) {
|
||||||
setContent(document.getElementById('template-add'));
|
document.querySelector('#template-add .add-save').textContent = chrome.i18n.getMessage('yes');
|
||||||
|
document.querySelector('#template-add .never-save').textContent = chrome.i18n.getMessage('never');
|
||||||
var add = $('#template-add-clone'),
|
|
||||||
addButton = $('#template-add-clone .add-save'),
|
|
||||||
neverButton = $('#template-add-clone .never-save');
|
|
||||||
|
|
||||||
$(addButton).click(function (e) {
|
|
||||||
e.preventDefault();
|
|
||||||
chrome.runtime.sendMessage({
|
|
||||||
command: 'bgAddSave'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$(neverButton).click(function (e) {
|
|
||||||
e.preventDefault();
|
|
||||||
chrome.runtime.sendMessage({
|
|
||||||
command: 'bgNeverSave'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else if (getQueryVariable('info')) {
|
|
||||||
setContent(document.getElementById('template-alert'));
|
|
||||||
$('#template-alert-clone').text(getQueryVariable('info'));
|
|
||||||
}
|
|
||||||
|
|
||||||
closeButton.click(function (e) {
|
|
||||||
e.preventDefault();
|
|
||||||
chrome.runtime.sendMessage({
|
|
||||||
command: 'bgCloseNotificationBar'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
chrome.runtime.sendMessage({
|
|
||||||
command: 'bgAdjustNotificationBar',
|
|
||||||
data: {
|
|
||||||
height: document.body.scrollHeight
|
|
||||||
}
|
}
|
||||||
});
|
else {
|
||||||
|
document.querySelector('#template-add .add-save').textContent = chrome.i18n.getMessage('notificationAddSave');
|
||||||
|
document.querySelector('#template-add .never-save').textContent = chrome.i18n.getMessage('notificationNeverSave');
|
||||||
|
}
|
||||||
|
|
||||||
|
document.querySelector('#template-add .add-text').textContent = chrome.i18n.getMessage('notificationAddDesc');
|
||||||
|
|
||||||
|
if (getQueryVariable('add')) {
|
||||||
|
setContent(document.getElementById('template-add'));
|
||||||
|
|
||||||
|
var addButton = document.querySelector('#template-add-clone .add-save'),
|
||||||
|
neverButton = document.querySelector('#template-add-clone .never-save');
|
||||||
|
|
||||||
|
addButton.addEventListener('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
chrome.runtime.sendMessage({
|
||||||
|
command: 'bgAddSave'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
neverButton.addEventListener('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
chrome.runtime.sendMessage({
|
||||||
|
command: 'bgNeverSave'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (getQueryVariable('info')) {
|
||||||
|
setContent(document.getElementById('template-alert'));
|
||||||
|
document.getElementById('template-alert-clone').textContent = getQueryVariable('info');
|
||||||
|
}
|
||||||
|
|
||||||
|
closeButton.addEventListener('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
chrome.runtime.sendMessage({
|
||||||
|
command: 'bgCloseNotificationBar'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
chrome.runtime.sendMessage({
|
||||||
|
command: 'bgAdjustNotificationBar',
|
||||||
|
data: {
|
||||||
|
height: body.scrollHeight
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function getQueryVariable(variable) {
|
function getQueryVariable(variable) {
|
||||||
var query = window.location.search.substring(1);
|
var query = window.location.search.substring(1);
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
angular
|
angular
|
||||||
.module('bit.accounts')
|
.module('bit.accounts')
|
||||||
|
|
||||||
.controller('accountsHintController', function ($scope, $state, apiService, toastr, $q, utilsService,
|
.controller('accountsHintController', function ($scope, $state, apiService, toastr, $q, utilsService,
|
||||||
$analytics, i18nService) {
|
$analytics, i18nService, $timeout) {
|
||||||
|
$timeout(function () {
|
||||||
|
utilsService.initListSectionItemListeners(document, angular);
|
||||||
|
document.getElementById('email').focus();
|
||||||
|
}, 500);
|
||||||
|
|
||||||
$scope.i18n = i18nService;
|
$scope.i18n = i18nService;
|
||||||
$scope.model = {};
|
$scope.model = {};
|
||||||
|
|
||||||
utilsService.initListSectionItemListeners($(document), angular);
|
|
||||||
$('#email').focus();
|
|
||||||
|
|
||||||
$scope.submitPromise = null;
|
$scope.submitPromise = null;
|
||||||
$scope.submit = function (model) {
|
$scope.submit = function (model) {
|
||||||
if (!model.email) {
|
if (!model.email) {
|
||||||
@ -31,13 +33,11 @@
|
|||||||
|
|
||||||
function hintPromise(request) {
|
function hintPromise(request) {
|
||||||
return $q(function (resolve, reject) {
|
return $q(function (resolve, reject) {
|
||||||
apiService.postPasswordHint(request,
|
apiService.postPasswordHint(request).then(function () {
|
||||||
function () {
|
resolve();
|
||||||
resolve();
|
}, function (error) {
|
||||||
},
|
reject(error);
|
||||||
function (error) {
|
});
|
||||||
reject(error);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
angular
|
angular
|
||||||
.module('bit.accounts')
|
.module('bit.accounts')
|
||||||
|
|
||||||
.controller('accountsLoginController', function ($scope, $state, $stateParams, authService, userService, toastr,
|
.controller('accountsLoginController', function ($scope, $state, $stateParams, authService, userService, toastr,
|
||||||
utilsService, $analytics, i18nService) {
|
utilsService, $analytics, i18nService, $timeout) {
|
||||||
utilsService.initListSectionItemListeners($(document), angular);
|
$timeout(function () {
|
||||||
|
utilsService.initListSectionItemListeners(document, angular);
|
||||||
|
if ($stateParams.email) {
|
||||||
|
document.getElementById('master-password').focus();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
document.getElementById('email').focus();
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
|
||||||
$scope.i18n = i18nService;
|
$scope.i18n = i18nService;
|
||||||
|
|
||||||
if ($stateParams.email) {
|
|
||||||
$('#master-password').focus();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$('#email').focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.model = {
|
$scope.model = {
|
||||||
email: $stateParams.email
|
email: $stateParams.email
|
||||||
};
|
};
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
angular
|
angular
|
||||||
.module('bit.accounts')
|
.module('bit.accounts')
|
||||||
|
|
||||||
.controller('accountsLoginTwoFactorController', function ($scope, $state, authService, toastr, utilsService, SweetAlert,
|
.controller('accountsLoginTwoFactorController', function ($scope, $state, authService, toastr, utilsService, SweetAlert,
|
||||||
$analytics, i18nService, $stateParams, $filter, constantsService, $timeout, $window, cryptoService, apiService,
|
$analytics, i18nService, $stateParams, $filter, constantsService, $timeout, $window, cryptoService, apiService,
|
||||||
environmentService) {
|
environmentService) {
|
||||||
|
$timeout(function () {
|
||||||
|
utilsService.initListSectionItemListeners(document, angular);
|
||||||
|
}, 500);
|
||||||
|
|
||||||
$scope.i18n = i18nService;
|
$scope.i18n = i18nService;
|
||||||
utilsService.initListSectionItemListeners($(document), angular);
|
|
||||||
|
|
||||||
var customWebVaultUrl = null;
|
var customWebVaultUrl = null;
|
||||||
if (environmentService.baseUrl) {
|
if (environmentService.baseUrl) {
|
||||||
@ -85,7 +88,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
var key = cryptoService.makeKey(masterPassword, email);
|
var key = cryptoService.makeKey(masterPassword, email);
|
||||||
cryptoService.hashPassword(masterPassword, key, function (hash) {
|
cryptoService.hashPassword(masterPassword, key).then(function (hash) {
|
||||||
var request = new TwoFactorEmailRequest(email, hash);
|
var request = new TwoFactorEmailRequest(email, hash);
|
||||||
apiService.postTwoFactorEmail(request, function () {
|
apiService.postTwoFactorEmail(request, function () {
|
||||||
if (doToast) {
|
if (doToast) {
|
||||||
@ -143,7 +146,10 @@
|
|||||||
u2f.cleanup();
|
u2f.cleanup();
|
||||||
|
|
||||||
$timeout(function () {
|
$timeout(function () {
|
||||||
$('#code').focus();
|
var codeInput = document.getElementById('code');
|
||||||
|
if (codeInput) {
|
||||||
|
codeInput.focus();
|
||||||
|
}
|
||||||
|
|
||||||
var params;
|
var params;
|
||||||
if ($scope.providerType === constants.twoFactorProvider.duo) {
|
if ($scope.providerType === constants.twoFactorProvider.duo) {
|
||||||
@ -153,8 +159,10 @@
|
|||||||
host: params.Host,
|
host: params.Host,
|
||||||
sig_request: params.Signature,
|
sig_request: params.Signature,
|
||||||
submit_callback: function (theForm) {
|
submit_callback: function (theForm) {
|
||||||
var response = $(theForm).find('input[name="sig_response"]').val();
|
var sigElement = theForm.querySelector('input[name="sig_response"]');
|
||||||
$scope.login(response);
|
if (sigElement) {
|
||||||
|
$scope.login(sigElement.value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
angular
|
angular
|
||||||
.module('bit.accounts')
|
.module('bit.accounts')
|
||||||
|
|
||||||
.controller(
|
.controller(
|
||||||
'accountsRegisterController',
|
'accountsRegisterController',
|
||||||
function ($scope, $state, cryptoService, toastr, $q, apiService, utilsService, $analytics, i18nService) {
|
function ($scope, $state, cryptoService, toastr, $q, apiService, utilsService, $analytics, i18nService, $timeout) {
|
||||||
|
$timeout(function () {
|
||||||
|
utilsService.initListSectionItemListeners(document, angular);
|
||||||
|
document.getElementById('email').focus();
|
||||||
|
}, 500);
|
||||||
|
|
||||||
$scope.i18n = i18nService;
|
$scope.i18n = i18nService;
|
||||||
|
|
||||||
$scope.model = {};
|
$scope.model = {};
|
||||||
utilsService.initListSectionItemListeners($(document), angular);
|
|
||||||
$('#email').focus();
|
|
||||||
|
|
||||||
$scope.submitPromise = null;
|
$scope.submitPromise = null;
|
||||||
$scope.submit = function (model) {
|
$scope.submit = function (model) {
|
||||||
if (!model.email) {
|
if (!model.email) {
|
||||||
@ -45,16 +46,16 @@
|
|||||||
|
|
||||||
function registerPromise(key, masterPassword, email, hint) {
|
function registerPromise(key, masterPassword, email, hint) {
|
||||||
var deferred = $q.defer();
|
var deferred = $q.defer();
|
||||||
cryptoService.makeEncKey(key).then(function (encKey) {
|
var encKey;
|
||||||
cryptoService.hashPassword(masterPassword, key, function (hashedPassword) {
|
cryptoService.makeEncKey(key).then(function (theEncKey) {
|
||||||
var request = new RegisterRequest(email, hashedPassword, hint, encKey.encryptedString);
|
encKey = theEncKey;
|
||||||
apiService.postRegister(request,
|
return cryptoService.hashPassword(masterPassword, key);
|
||||||
function () {
|
}).then(function (hashedPassword) {
|
||||||
deferred.resolve();
|
var request = new RegisterRequest(email, hashedPassword, hint, encKey.encryptedString);
|
||||||
},
|
apiService.postRegister(request).then(function () {
|
||||||
function (error) {
|
deferred.resolve();
|
||||||
deferred.reject(error);
|
}, function (error) {
|
||||||
});
|
deferred.reject(error);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
|
@ -86,7 +86,7 @@
|
|||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="two-factor-key-page">
|
<div class="two-factor-key-page">
|
||||||
<p>{{i18n.insertYubiKey}}</p>
|
<p>{{i18n.insertYubiKey}}</p>
|
||||||
<img src="../images/two-factor/yubikey.jpg" alt="" class="img-rounded img-responsive" />
|
<img src="../../../../images/two-factor/yubikey.jpg" alt="" class="img-rounded img-responsive" />
|
||||||
</div>
|
</div>
|
||||||
<div class="list">
|
<div class="list">
|
||||||
<div class="list-section">
|
<div class="list-section">
|
||||||
@ -125,7 +125,7 @@
|
|||||||
<p ng-if="!u2fReady">Loading...</p>
|
<p ng-if="!u2fReady">Loading...</p>
|
||||||
<div ng-if="u2fReady">
|
<div ng-if="u2fReady">
|
||||||
<p>{{i18n.insertU2f}}</p>
|
<p>{{i18n.insertU2f}}</p>
|
||||||
<img src="../images/two-factor/u2fkey.jpg" alt="" class="img-rounded img-responsive" />
|
<img src="../../../../images/two-factor/u2fkey.jpg" alt="" class="img-rounded img-responsive" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="list">
|
<div class="list">
|
||||||
|
1
src/popup/app/app.d.ts
vendored
Normal file
1
src/popup/app/app.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
declare module '*.html';
|
@ -1,20 +1,139 @@
|
|||||||
angular
|
window.Papa = require('papaparse');
|
||||||
|
require('clipboard');
|
||||||
|
|
||||||
|
require('angular');
|
||||||
|
|
||||||
|
require('angular-animate');
|
||||||
|
const uiRouter = require('@uirouter/angularjs').default;
|
||||||
|
require('angular-toastr');
|
||||||
|
|
||||||
|
require('ngclipboard');
|
||||||
|
|
||||||
|
require('sweetalert');
|
||||||
|
require('angular-sweetalert');
|
||||||
|
require('angulartics');
|
||||||
|
require('angulartics-google-analytics');
|
||||||
|
require('ng-infinite-scroll');
|
||||||
|
|
||||||
|
require('../../scripts/analytics.js');
|
||||||
|
require('../../scripts/duo.js');
|
||||||
|
require('../../scripts/u2f.js');
|
||||||
|
|
||||||
|
require('../less/libs.less');
|
||||||
|
require('../less/popup.less');
|
||||||
|
|
||||||
|
import ComponentsModule from './components/components.module';
|
||||||
|
import ToolsModule from './tools/tools.module';
|
||||||
|
import ServicesModule from './services/services.module';
|
||||||
|
import LockModule from './lock/lock.module';
|
||||||
|
|
||||||
|
// Model imports
|
||||||
|
import { Attachment } from '../../models/domain/attachment';
|
||||||
|
import { Card } from '../../models/domain/card';
|
||||||
|
import { Cipher } from '../../models/domain/cipher';
|
||||||
|
import { Field } from '../../models/domain/field';
|
||||||
|
import { Folder } from '../../models/domain/folder';
|
||||||
|
import { Identity } from '../../models/domain/identity';
|
||||||
|
import { Login } from '../../models/domain/login';
|
||||||
|
import { SecureNote } from '../../models/domain/secureNote';
|
||||||
|
|
||||||
|
import { AttachmentData } from '../../models/data/attachmentData';
|
||||||
|
import { CardData } from '../../models/data/cardData';
|
||||||
|
import { CipherData } from '../../models/data/cipherData';
|
||||||
|
import { FieldData } from '../../models/data/fieldData';
|
||||||
|
import { FolderData } from '../../models/data/folderData';
|
||||||
|
import { IdentityData } from '../../models/data/identityData';
|
||||||
|
import { LoginData } from '../../models/data/loginData';
|
||||||
|
import { SecureNoteData } from '../../models/data/secureNoteData';
|
||||||
|
|
||||||
|
import { CipherString } from '../../models/domain/cipherString';
|
||||||
|
|
||||||
|
import { CipherRequest } from '../../models/request/cipherRequest';
|
||||||
|
import { DeviceRequest } from '../../models/request/deviceRequest';
|
||||||
|
import { DeviceTokenRequest } from '../../models/request/deviceTokenRequest';
|
||||||
|
import { FolderRequest } from '../../models/request/folderRequest';
|
||||||
|
import { PasswordHintRequest } from '../../models/request/passwordHintRequest';
|
||||||
|
import { RegisterRequest } from '../../models/request/registerRequest';
|
||||||
|
import { TokenRequest } from '../../models/request/tokenRequest';
|
||||||
|
import { TwoFactorEmailRequest } from '../../models/request/twoFactorEmailRequest';
|
||||||
|
|
||||||
|
import { AttachmentResponse } from '../../models/response/attachmentResponse';
|
||||||
|
import { CipherResponse } from '../../models/response/cipherResponse';
|
||||||
|
import { DeviceResponse } from '../../models/response/deviceResponse';
|
||||||
|
import { DomainsResponse } from '../../models/response/domainsResponse';
|
||||||
|
import { ErrorResponse } from '../../models/response/errorResponse';
|
||||||
|
import { FolderResponse } from '../../models/response/folderResponse';
|
||||||
|
import { GlobalDomainResponse } from '../../models/response/globalDomainResponse';
|
||||||
|
import { IdentityTokenResponse } from '../../models/response/identityTokenResponse';
|
||||||
|
import { KeysResponse } from '../../models/response/keysResponse';
|
||||||
|
import { ListResponse } from '../../models/response/listResponse';
|
||||||
|
import { ProfileOrganizationResponse } from '../../models/response/profileOrganizationResponse';
|
||||||
|
import { ProfileResponse } from '../../models/response/profileResponse';
|
||||||
|
import { SyncResponse } from '../../models/response/syncResponse';
|
||||||
|
|
||||||
|
angular
|
||||||
.module('bit', [
|
.module('bit', [
|
||||||
'ui.router',
|
uiRouter,
|
||||||
'ngAnimate',
|
'ngAnimate',
|
||||||
'toastr',
|
'toastr',
|
||||||
'angulartics',
|
'angulartics',
|
||||||
'angulartics.google.analytics',
|
'angulartics.google.analytics',
|
||||||
|
|
||||||
'bit.directives',
|
'bit.directives',
|
||||||
'bit.components',
|
ComponentsModule,
|
||||||
'bit.services',
|
ServicesModule,
|
||||||
|
|
||||||
'bit.global',
|
'bit.global',
|
||||||
'bit.accounts',
|
'bit.accounts',
|
||||||
'bit.current',
|
'bit.current',
|
||||||
'bit.vault',
|
'bit.vault',
|
||||||
'bit.settings',
|
'bit.settings',
|
||||||
'bit.tools',
|
ToolsModule,
|
||||||
'bit.lock'
|
LockModule
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
require('./config');
|
||||||
|
require('./directives/directivesModule.js');
|
||||||
|
require('./directives/formDirective.js');
|
||||||
|
require('./directives/stopClickDirective.js');
|
||||||
|
require('./directives/stopPropDirective.js');
|
||||||
|
require('./directives/fallbackSrcDirective.js');
|
||||||
|
require('./global/globalModule.js');
|
||||||
|
require('./global/mainController.js');
|
||||||
|
require('./global/tabsController.js');
|
||||||
|
require('./global/baseController.js');
|
||||||
|
require('./global/privateModeController.js');
|
||||||
|
require('./accounts/accountsModule.js');
|
||||||
|
require('./accounts/accountsLoginController.js');
|
||||||
|
require('./accounts/accountsLoginTwoFactorController.js');
|
||||||
|
require('./accounts/accountsTwoFactorMethodsController.js');
|
||||||
|
require('./accounts/accountsHintController.js');
|
||||||
|
require('./accounts/accountsRegisterController.js');
|
||||||
|
require('./current/currentModule.js');
|
||||||
|
require('./current/currentController.js');
|
||||||
|
require('./vault/vaultModule.js');
|
||||||
|
require('./vault/vaultController.js');
|
||||||
|
require('./vault/vaultViewFolderController.js');
|
||||||
|
require('./vault/vaultAddCipherController.js');
|
||||||
|
require('./vault/vaultEditCipherController.js');
|
||||||
|
require('./vault/vaultViewCipherController.js');
|
||||||
|
require('./vault/vaultAttachmentsController.js');
|
||||||
|
require('./settings/settingsModule.js');
|
||||||
|
require('./settings/settingsController.js');
|
||||||
|
require('./settings/settingsHelpController.js');
|
||||||
|
require('./settings/settingsAboutController.js');
|
||||||
|
require('./settings/settingsCreditsController.js');
|
||||||
|
require('./settings/settingsFeaturesController.js');
|
||||||
|
require('./settings/settingsSyncController.js');
|
||||||
|
require('./settings/settingsFoldersController.js');
|
||||||
|
require('./settings/settingsAddFolderController.js');
|
||||||
|
require('./settings/settingsEditFolderController.js');
|
||||||
|
require('./settings/settingsPremiumController.js');
|
||||||
|
require('./settings/settingsEnvironmentController.js');
|
||||||
|
require('./tools/toolsPasswordGeneratorHistoryController.js');
|
||||||
|
require('./tools/toolsExportController.js');
|
||||||
|
|
||||||
|
// Bootstrap the angular application
|
||||||
|
angular.element(function () {
|
||||||
|
angular.bootstrap(document, ['bit']);
|
||||||
|
});
|
||||||
|
49
src/popup/app/components/action-buttons.component.ts
Normal file
49
src/popup/app/components/action-buttons.component.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import * as template from './action-buttons.component.html';
|
||||||
|
|
||||||
|
class ActionButtonsController implements ng.IController {
|
||||||
|
onView: Function;
|
||||||
|
|
||||||
|
cipher: any;
|
||||||
|
showView: boolean;
|
||||||
|
i18n: any;
|
||||||
|
constants: any;
|
||||||
|
|
||||||
|
constructor(private i18nService: any, private $analytics: any, private constantsService: any, private toastr: any,
|
||||||
|
private $timeout: any, private $window: any, private utilsService: any) {
|
||||||
|
this.i18n = i18nService;
|
||||||
|
this.constants = constantsService;
|
||||||
|
}
|
||||||
|
|
||||||
|
launch() {
|
||||||
|
const self = this;
|
||||||
|
this.$timeout(() => {
|
||||||
|
if (self.cipher.login.uri.startsWith('http://') || self.cipher.login.uri.startsWith('https://')) {
|
||||||
|
self.$analytics.eventTrack('Launched Website From Listing');
|
||||||
|
chrome.tabs.create({ url: self.cipher.login.uri });
|
||||||
|
if (self.utilsService.inPopup(self.$window)) {
|
||||||
|
self.$window.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
clipboardError(e: any) {
|
||||||
|
this.toastr.info(this.i18nService.browserNotSupportClipboard);
|
||||||
|
}
|
||||||
|
|
||||||
|
clipboardSuccess(e: any, type: string, aType: string) {
|
||||||
|
e.clearSelection();
|
||||||
|
this.$analytics.eventTrack('Copied ' + aType);
|
||||||
|
this.toastr.info(type + this.i18nService.valueCopied);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ActionButtonsComponent = {
|
||||||
|
bindings: {
|
||||||
|
cipher: '<',
|
||||||
|
showView: '<',
|
||||||
|
onView: '&',
|
||||||
|
},
|
||||||
|
controller: ActionButtonsController,
|
||||||
|
template,
|
||||||
|
};
|
@ -1,41 +0,0 @@
|
|||||||
angular
|
|
||||||
.module('bit.components')
|
|
||||||
|
|
||||||
.component('actionButtons', {
|
|
||||||
bindings: {
|
|
||||||
cipher: '<',
|
|
||||||
showView: '<',
|
|
||||||
onView: '&'
|
|
||||||
},
|
|
||||||
templateUrl: 'app/components/views/actionButtons.html',
|
|
||||||
controller: function (i18nService, $analytics, constantsService, toastr, $timeout, $window, utilsService) {
|
|
||||||
var ctrl = this;
|
|
||||||
|
|
||||||
ctrl.$onInit = function () {
|
|
||||||
ctrl.i18n = i18nService;
|
|
||||||
ctrl.constants = constantsService;
|
|
||||||
|
|
||||||
ctrl.launch = function () {
|
|
||||||
$timeout(function () {
|
|
||||||
if (ctrl.cipher.login.uri.startsWith('http://') || ctrl.cipher.login.uri.startsWith('https://')) {
|
|
||||||
$analytics.eventTrack('Launched Website From Listing');
|
|
||||||
chrome.tabs.create({ url: ctrl.cipher.login.uri });
|
|
||||||
if (utilsService.inPopup($window)) {
|
|
||||||
$window.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
ctrl.clipboardError = function (e) {
|
|
||||||
toastr.info(i18nService.browserNotSupportClipboard);
|
|
||||||
};
|
|
||||||
|
|
||||||
ctrl.clipboardSuccess = function (e, type, aType) {
|
|
||||||
e.clearSelection();
|
|
||||||
$analytics.eventTrack('Copied ' + aType);
|
|
||||||
toastr.info(type + i18nService.valueCopied);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
29
src/popup/app/components/cipher-items.component.ts
Normal file
29
src/popup/app/components/cipher-items.component.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import * as template from './cipher-items.component.html';
|
||||||
|
|
||||||
|
class CipherItemsController implements ng.IController {
|
||||||
|
onSelected: Function;
|
||||||
|
onView: Function;
|
||||||
|
|
||||||
|
constructor(private i18nService: any) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
view(cipher: any) {
|
||||||
|
return this.onView()(cipher);
|
||||||
|
}
|
||||||
|
|
||||||
|
select(cipher: any) {
|
||||||
|
return this.onSelected()(cipher);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CipherItemsComponent = {
|
||||||
|
bindings: {
|
||||||
|
ciphers: '<',
|
||||||
|
selectionTitle: '<',
|
||||||
|
onSelected: '&',
|
||||||
|
onView: '&',
|
||||||
|
},
|
||||||
|
controller: CipherItemsController,
|
||||||
|
template,
|
||||||
|
};
|
@ -1,27 +0,0 @@
|
|||||||
angular
|
|
||||||
.module('bit.components')
|
|
||||||
|
|
||||||
.component('cipherItems', {
|
|
||||||
bindings: {
|
|
||||||
ciphers: '<',
|
|
||||||
selectionTitle: '<',
|
|
||||||
onView: '&',
|
|
||||||
onSelected: '&'
|
|
||||||
},
|
|
||||||
templateUrl: 'app/components/views/cipherItems.html',
|
|
||||||
controller: function (i18nService) {
|
|
||||||
var ctrl = this;
|
|
||||||
|
|
||||||
ctrl.$onInit = function () {
|
|
||||||
ctrl.i18n = i18nService;
|
|
||||||
|
|
||||||
ctrl.view = function (cipher) {
|
|
||||||
ctrl.onView()(cipher);
|
|
||||||
};
|
|
||||||
|
|
||||||
ctrl.select = function (cipher) {
|
|
||||||
ctrl.onSelected()(cipher);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
11
src/popup/app/components/components.module.ts
Normal file
11
src/popup/app/components/components.module.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import * as angular from 'angular';
|
||||||
|
import { ActionButtonsComponent } from './action-buttons.component';
|
||||||
|
import { CipherItemsComponent } from './cipher-items.component';
|
||||||
|
import { IconComponent } from './icon.component';
|
||||||
|
|
||||||
|
export default angular
|
||||||
|
.module('bit.components', [])
|
||||||
|
.component('cipherItems', CipherItemsComponent)
|
||||||
|
.component('icon', IconComponent)
|
||||||
|
.component('actionButtons', ActionButtonsComponent)
|
||||||
|
.name;
|
@ -1,2 +0,0 @@
|
|||||||
angular
|
|
||||||
.module('bit.components', []);
|
|
@ -1,4 +1,4 @@
|
|||||||
<div class="icon">
|
<div class="icon">
|
||||||
<img ng-src="{{$ctrl.image}}" fallback-src="{{$ctrl.fallbackImage}}" ng-if="$ctrl.imageEnabled && $ctrl.image" alt="" />
|
<img ng-src="{{$ctrl.image}}" fallback-src="{{$ctrl.fallbackImage}}" ng-if="$ctrl.imageEnabled && $ctrl.image" alt="" />
|
||||||
<i class="fa fa-fw fa-lg {{$ctrl.icon}}" ng-if="!$ctrl.imageEnabled || !$ctrl.image"></i>
|
<i class="fa fa-fw fa-lg {{$ctrl.icon}}" ng-if="!$ctrl.imageEnabled || !$ctrl.image"></i>
|
||||||
</div>
|
</div>
|
82
src/popup/app/components/icon.component.ts
Normal file
82
src/popup/app/components/icon.component.ts
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import * as template from './icon.component.html';
|
||||||
|
|
||||||
|
class IconController implements ng.IController {
|
||||||
|
cipher: any;
|
||||||
|
icon: string;
|
||||||
|
image: string;
|
||||||
|
fallbackImage: string;
|
||||||
|
imageEnabled: boolean;
|
||||||
|
|
||||||
|
private iconsUrl: string;
|
||||||
|
|
||||||
|
constructor(private stateService: any, private constantsService: any, private environmentService: any) {
|
||||||
|
this.imageEnabled = stateService.getState('faviconEnabled');
|
||||||
|
|
||||||
|
this.iconsUrl = environmentService.iconsUrl;
|
||||||
|
if (!this.iconsUrl) {
|
||||||
|
if (environmentService.baseUrl) {
|
||||||
|
this.iconsUrl = environmentService.baseUrl + '/icons';
|
||||||
|
} else {
|
||||||
|
this.iconsUrl = 'https://icons.bitwarden.com';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$onChanges() {
|
||||||
|
switch (this.cipher.type) {
|
||||||
|
case this.constantsService.cipherType.login:
|
||||||
|
this.icon = 'fa-globe';
|
||||||
|
this.setLoginIcon();
|
||||||
|
break;
|
||||||
|
case this.constantsService.cipherType.secureNote:
|
||||||
|
this.icon = 'fa-sticky-note-o';
|
||||||
|
break;
|
||||||
|
case this.constantsService.cipherType.card:
|
||||||
|
this.icon = 'fa-credit-card';
|
||||||
|
break;
|
||||||
|
case this.constantsService.cipherType.identity:
|
||||||
|
this.icon = 'fa-id-card-o';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private setLoginIcon() {
|
||||||
|
if (this.cipher.login.uri) {
|
||||||
|
let hostnameUri = this.cipher.login.uri;
|
||||||
|
let isWebsite = false;
|
||||||
|
|
||||||
|
if (hostnameUri.indexOf('androidapp://') === 0) {
|
||||||
|
this.icon = 'fa-android';
|
||||||
|
this.image = null;
|
||||||
|
} else if (hostnameUri.indexOf('iosapp://') === 0) {
|
||||||
|
this.icon = 'fa-apple';
|
||||||
|
this.image = null;
|
||||||
|
} else if (this.imageEnabled && hostnameUri.indexOf('://') === -1 && hostnameUri.indexOf('.') > -1) {
|
||||||
|
hostnameUri = 'http://' + hostnameUri;
|
||||||
|
isWebsite = true;
|
||||||
|
} else if (this.imageEnabled) {
|
||||||
|
isWebsite = hostnameUri.indexOf('http') === 0 && hostnameUri.indexOf('.') > -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.imageEnabled && isWebsite) {
|
||||||
|
try {
|
||||||
|
const url = new URL(hostnameUri);
|
||||||
|
this.image = this.iconsUrl + '/' + url.hostname + '/icon.png';
|
||||||
|
this.fallbackImage = chrome.extension.getURL('images/fa-globe.png');
|
||||||
|
} catch (e) { }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.image = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const IconComponent = {
|
||||||
|
bindings: {
|
||||||
|
cipher: '<',
|
||||||
|
},
|
||||||
|
controller: IconController,
|
||||||
|
template,
|
||||||
|
};
|
@ -1,78 +0,0 @@
|
|||||||
angular
|
|
||||||
.module('bit.components')
|
|
||||||
|
|
||||||
.component('icon', {
|
|
||||||
bindings: {
|
|
||||||
cipher: '<'
|
|
||||||
},
|
|
||||||
templateUrl: 'app/components/views/icon.html',
|
|
||||||
controller: function (stateService, constantsService, environmentService) {
|
|
||||||
var ctrl = this;
|
|
||||||
ctrl.imageEnabled = stateService.getState('faviconEnabled');
|
|
||||||
|
|
||||||
var iconsUrl = environmentService.iconsUrl;
|
|
||||||
if (!iconsUrl) {
|
|
||||||
if (environmentService.baseUrl) {
|
|
||||||
iconsUrl = environmentService.baseUrl + '/icons';
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
iconsUrl = 'https://icons.bitwarden.com';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctrl.$onChanges = function () {
|
|
||||||
switch (ctrl.cipher.type) {
|
|
||||||
case constantsService.cipherType.login:
|
|
||||||
ctrl.icon = 'fa-globe';
|
|
||||||
setLoginIcon(ctrl.cipher);
|
|
||||||
break;
|
|
||||||
case constantsService.cipherType.secureNote:
|
|
||||||
ctrl.icon = 'fa-sticky-note-o';
|
|
||||||
break;
|
|
||||||
case constantsService.cipherType.card:
|
|
||||||
ctrl.icon = 'fa-credit-card';
|
|
||||||
break;
|
|
||||||
case constantsService.cipherType.identity:
|
|
||||||
ctrl.icon = 'fa-id-card-o';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function setLoginIcon() {
|
|
||||||
if (ctrl.cipher.login.uri) {
|
|
||||||
var hostnameUri = ctrl.cipher.login.uri,
|
|
||||||
isWebsite = false;
|
|
||||||
|
|
||||||
if (hostnameUri.indexOf('androidapp://') === 0) {
|
|
||||||
ctrl.icon = 'fa-android';
|
|
||||||
ctrl.image = null;
|
|
||||||
}
|
|
||||||
else if (hostnameUri.indexOf('iosapp://') === 0) {
|
|
||||||
ctrl.icon = 'fa-apple';
|
|
||||||
ctrl.image = null;
|
|
||||||
}
|
|
||||||
else if (ctrl.imageEnabled && hostnameUri.indexOf('://') === -1 && hostnameUri.indexOf('.') > -1) {
|
|
||||||
hostnameUri = "http://" + hostnameUri;
|
|
||||||
isWebsite = true;
|
|
||||||
}
|
|
||||||
else if (ctrl.imageEnabled) {
|
|
||||||
isWebsite = hostnameUri.indexOf('http') === 0 && hostnameUri.indexOf('.') > -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ctrl.imageEnabled && isWebsite) {
|
|
||||||
try {
|
|
||||||
var url = new URL(hostnameUri);
|
|
||||||
ctrl.image = iconsUrl + '/' + url.hostname + '/icon.png';
|
|
||||||
ctrl.fallbackImage = chrome.extension.getURL('images/fa-globe.png');
|
|
||||||
}
|
|
||||||
catch (e) { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ctrl.image = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,4 +1,4 @@
|
|||||||
angular
|
angular
|
||||||
.module('bit')
|
.module('bit')
|
||||||
|
|
||||||
.config(function ($stateProvider, $urlRouterProvider, $compileProvider, $sceDelegateProvider, toastrConfig) {
|
.config(function ($stateProvider, $urlRouterProvider, $compileProvider, $sceDelegateProvider, toastrConfig) {
|
||||||
@ -23,20 +23,22 @@
|
|||||||
var userService = $injector.get('userService');
|
var userService = $injector.get('userService');
|
||||||
var cryptoService = $injector.get('cryptoService');
|
var cryptoService = $injector.get('cryptoService');
|
||||||
|
|
||||||
cryptoService.getKey().then(function (key) {
|
var key;
|
||||||
userService.isAuthenticated(function (isAuthenticated) {
|
cryptoService.getKey().then(function (theKey) {
|
||||||
if (isAuthenticated) {
|
key = theKey;
|
||||||
if (!key) {
|
return userService.isAuthenticated();
|
||||||
$state.go('lock');
|
}).then(function (isAuthenticated) {
|
||||||
}
|
if (isAuthenticated) {
|
||||||
else {
|
if (!key) {
|
||||||
$state.go('tabs.current');
|
$state.go('lock');
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$state.go('home');
|
$state.go('tabs.current');
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
else {
|
||||||
|
$state.go('home');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -44,21 +46,21 @@
|
|||||||
.state('splash', {
|
.state('splash', {
|
||||||
url: '/splash',
|
url: '/splash',
|
||||||
controller: 'baseController',
|
controller: 'baseController',
|
||||||
templateUrl: 'app/global/splash.html',
|
template: require('./global/splash.html'),
|
||||||
data: { authorize: false },
|
data: { authorize: false },
|
||||||
params: { animation: null }
|
params: { animation: null }
|
||||||
})
|
})
|
||||||
.state('privateMode', {
|
.state('privateMode', {
|
||||||
url: '/private-mode',
|
url: '/private-mode',
|
||||||
controller: 'privateModeController',
|
controller: 'privateModeController',
|
||||||
templateUrl: 'app/global/privateMode.html',
|
template: require('./global/privateMode.html'),
|
||||||
data: { authorize: false },
|
data: { authorize: false },
|
||||||
params: { animation: null }
|
params: { animation: null }
|
||||||
})
|
})
|
||||||
.state('home', {
|
.state('home', {
|
||||||
url: '/home',
|
url: '/home',
|
||||||
controller: 'baseController',
|
controller: 'baseController',
|
||||||
templateUrl: 'app/global/home.html',
|
template: require('./global/home.html'),
|
||||||
data: { authorize: false },
|
data: { authorize: false },
|
||||||
params: { animation: null }
|
params: { animation: null }
|
||||||
})
|
})
|
||||||
@ -66,35 +68,35 @@
|
|||||||
.state('login', {
|
.state('login', {
|
||||||
url: '/login',
|
url: '/login',
|
||||||
controller: 'accountsLoginController',
|
controller: 'accountsLoginController',
|
||||||
templateUrl: 'app/accounts/views/accountsLogin.html',
|
template: require('./accounts/views/accountsLogin.html'),
|
||||||
data: { authorize: false },
|
data: { authorize: false },
|
||||||
params: { animation: null, email: null }
|
params: { animation: null, email: null }
|
||||||
})
|
})
|
||||||
.state('hint', {
|
.state('hint', {
|
||||||
url: '/hint',
|
url: '/hint',
|
||||||
controller: 'accountsHintController',
|
controller: 'accountsHintController',
|
||||||
templateUrl: 'app/accounts/views/accountsHint.html',
|
template: require('./accounts/views/accountsHint.html'),
|
||||||
data: { authorize: false },
|
data: { authorize: false },
|
||||||
params: { animation: null }
|
params: { animation: null }
|
||||||
})
|
})
|
||||||
.state('twoFactor', {
|
.state('twoFactor', {
|
||||||
url: '/two-factor',
|
url: '/two-factor',
|
||||||
controller: 'accountsLoginTwoFactorController',
|
controller: 'accountsLoginTwoFactorController',
|
||||||
templateUrl: 'app/accounts/views/accountsLoginTwoFactor.html',
|
template: require('./accounts/views/accountsLoginTwoFactor.html'),
|
||||||
data: { authorize: false },
|
data: { authorize: false },
|
||||||
params: { animation: null, email: null, masterPassword: null, providers: null, provider: null }
|
params: { animation: null, email: null, masterPassword: null, providers: null, provider: null }
|
||||||
})
|
})
|
||||||
.state('twoFactorMethods', {
|
.state('twoFactorMethods', {
|
||||||
url: '/two-factor-methods',
|
url: '/two-factor-methods',
|
||||||
controller: 'accountsTwoFactorMethodsController',
|
controller: 'accountsTwoFactorMethodsController',
|
||||||
templateUrl: 'app/accounts/views/accountsTwoFactorMethods.html',
|
template: require('./accounts/views/accountsTwoFactorMethods.html'),
|
||||||
data: { authorize: false },
|
data: { authorize: false },
|
||||||
params: { animation: null, email: null, masterPassword: null, providers: null, provider: null }
|
params: { animation: null, email: null, masterPassword: null, providers: null, provider: null }
|
||||||
})
|
})
|
||||||
.state('register', {
|
.state('register', {
|
||||||
url: '/register',
|
url: '/register',
|
||||||
controller: 'accountsRegisterController',
|
controller: 'accountsRegisterController',
|
||||||
templateUrl: 'app/accounts/views/accountsRegister.html',
|
template: require('./accounts/views/accountsRegister.html'),
|
||||||
data: { authorize: false },
|
data: { authorize: false },
|
||||||
params: { animation: null }
|
params: { animation: null }
|
||||||
})
|
})
|
||||||
@ -102,63 +104,62 @@
|
|||||||
.state('tabs', {
|
.state('tabs', {
|
||||||
url: '/tab',
|
url: '/tab',
|
||||||
abstract: true,
|
abstract: true,
|
||||||
templateUrl: 'app/global/tabs.html',
|
template: require('./global/tabs.html'),
|
||||||
data: { authorize: true },
|
data: { authorize: true },
|
||||||
params: { animation: null }
|
params: { animation: null }
|
||||||
})
|
})
|
||||||
.state('tabs.current', {
|
.state('tabs.current', {
|
||||||
url: '/current',
|
url: '/current',
|
||||||
templateUrl: 'app/current/views/current.html',
|
template: require('./current/views/current.html'),
|
||||||
controller: 'currentController'
|
controller: 'currentController'
|
||||||
})
|
})
|
||||||
.state('tabs.vault', {
|
.state('tabs.vault', {
|
||||||
url: '/vault',
|
url: '/vault',
|
||||||
templateUrl: 'app/vault/views/vault.html',
|
template: require('./vault/views/vault.html'),
|
||||||
controller: 'vaultController',
|
controller: 'vaultController',
|
||||||
params: { syncOnLoad: false, searchText: null }
|
params: { syncOnLoad: false, searchText: null }
|
||||||
})
|
})
|
||||||
.state('tabs.settings', {
|
.state('tabs.settings', {
|
||||||
url: '/settings',
|
url: '/settings',
|
||||||
templateUrl: 'app/settings/views/settings.html',
|
template: require('./settings/views/settings.html'),
|
||||||
controller: 'settingsController'
|
controller: 'settingsController'
|
||||||
})
|
})
|
||||||
.state('tabs.tools', {
|
.state('tabs.tools', {
|
||||||
url: '/tools',
|
url: '/tools',
|
||||||
templateUrl: 'app/tools/views/tools.html',
|
component: 'tools'
|
||||||
controller: 'toolsController'
|
|
||||||
})
|
})
|
||||||
|
|
||||||
.state('viewFolder', {
|
.state('viewFolder', {
|
||||||
url: '/view-folder?folderId',
|
url: '/view-folder?folderId',
|
||||||
templateUrl: 'app/vault/views/vaultViewFolder.html',
|
template: require('./vault/views/vaultViewFolder.html'),
|
||||||
controller: 'vaultViewFolderController',
|
controller: 'vaultViewFolderController',
|
||||||
data: { authorize: true },
|
data: { authorize: true },
|
||||||
params: { animation: null, from: 'vault' }
|
params: { animation: null, from: 'vault' }
|
||||||
})
|
})
|
||||||
.state('viewCipher', {
|
.state('viewCipher', {
|
||||||
url: '/view-cipher?cipherId',
|
url: '/view-cipher?cipherId',
|
||||||
templateUrl: 'app/vault/views/vaultViewCipher.html',
|
template: require('./vault/views/vaultViewCipher.html'),
|
||||||
controller: 'vaultViewCipherController',
|
controller: 'vaultViewCipherController',
|
||||||
data: { authorize: true },
|
data: { authorize: true },
|
||||||
params: { animation: null, from: 'vault' }
|
params: { animation: null, from: 'vault' }
|
||||||
})
|
})
|
||||||
.state('addCipher', {
|
.state('addCipher', {
|
||||||
url: '/add-cipher',
|
url: '/add-cipher',
|
||||||
templateUrl: 'app/vault/views/vaultAddCipher.html',
|
template: require('./vault/views/vaultAddCipher.html'),
|
||||||
controller: 'vaultAddCipherController',
|
controller: 'vaultAddCipherController',
|
||||||
data: { authorize: true },
|
data: { authorize: true },
|
||||||
params: { animation: null, name: null, uri: null, folderId: null, cipher: null, from: 'vault' }
|
params: { animation: null, name: null, uri: null, folderId: null, cipher: null, from: 'vault' }
|
||||||
})
|
})
|
||||||
.state('editCipher', {
|
.state('editCipher', {
|
||||||
url: '/edit-cipher?cipherId',
|
url: '/edit-cipher?cipherId',
|
||||||
templateUrl: 'app/vault/views/vaultEditCipher.html',
|
template: require('./vault/views/vaultEditCipher.html'),
|
||||||
controller: 'vaultEditCipherController',
|
controller: 'vaultEditCipherController',
|
||||||
data: { authorize: true },
|
data: { authorize: true },
|
||||||
params: { animation: null, fromView: true, cipher: null, from: 'vault' }
|
params: { animation: null, fromView: true, cipher: null, from: 'vault' }
|
||||||
})
|
})
|
||||||
.state('attachments', {
|
.state('attachments', {
|
||||||
url: '/attachments?id',
|
url: '/attachments?id',
|
||||||
templateUrl: 'app/vault/views/vaultAttachments.html',
|
template: require('./vault/views/vaultAttachments.html'),
|
||||||
controller: 'vaultAttachmentsController',
|
controller: 'vaultAttachmentsController',
|
||||||
data: { authorize: true },
|
data: { authorize: true },
|
||||||
params: { animation: null, fromView: true, from: 'vault' }
|
params: { animation: null, fromView: true, from: 'vault' }
|
||||||
@ -166,21 +167,20 @@
|
|||||||
|
|
||||||
.state('passwordGenerator', {
|
.state('passwordGenerator', {
|
||||||
url: '/password-generator',
|
url: '/password-generator',
|
||||||
templateUrl: 'app/tools/views/toolsPasswordGenerator.html',
|
component: 'passwordGenerator',
|
||||||
controller: 'toolsPasswordGeneratorController',
|
|
||||||
data: { authorize: true },
|
data: { authorize: true },
|
||||||
params: { animation: null, addState: null, editState: null }
|
params: { animation: null, addState: null, editState: null }
|
||||||
})
|
})
|
||||||
.state('passwordGeneratorHistory', {
|
.state('passwordGeneratorHistory', {
|
||||||
url: '/history',
|
url: '/history',
|
||||||
templateUrl: 'app/tools/views/toolsPasswordGeneratorHistory.html',
|
template: require('./tools/views/toolsPasswordGeneratorHistory.html'),
|
||||||
controller: 'toolsPasswordGeneratorHistoryController',
|
controller: 'toolsPasswordGeneratorHistoryController',
|
||||||
data: { authorize: true },
|
data: { authorize: true },
|
||||||
params: { animation: null, addState: null, editState: null }
|
params: { animation: null, addState: null, editState: null }
|
||||||
})
|
})
|
||||||
.state('export', {
|
.state('export', {
|
||||||
url: '/export',
|
url: '/export',
|
||||||
templateUrl: 'app/tools/views/toolsExport.html',
|
template: require('./tools/views/toolsExport.html'),
|
||||||
controller: 'toolsExportController',
|
controller: 'toolsExportController',
|
||||||
data: { authorize: true },
|
data: { authorize: true },
|
||||||
params: { animation: null }
|
params: { animation: null }
|
||||||
@ -188,42 +188,42 @@
|
|||||||
|
|
||||||
.state('about', {
|
.state('about', {
|
||||||
url: '/about',
|
url: '/about',
|
||||||
templateUrl: 'app/settings/views/settingsAbout.html',
|
template: require('./settings/views/settingsAbout.html'),
|
||||||
controller: 'settingsAboutController',
|
controller: 'settingsAboutController',
|
||||||
data: { authorize: true },
|
data: { authorize: true },
|
||||||
params: { animation: null }
|
params: { animation: null }
|
||||||
})
|
})
|
||||||
.state('credits', {
|
.state('credits', {
|
||||||
url: '/credits',
|
url: '/credits',
|
||||||
templateUrl: 'app/settings/views/settingsCredits.html',
|
template: require('./settings/views/settingsCredits.html'),
|
||||||
controller: 'settingsCreditsController',
|
controller: 'settingsCreditsController',
|
||||||
data: { authorize: true },
|
data: { authorize: true },
|
||||||
params: { animation: null }
|
params: { animation: null }
|
||||||
})
|
})
|
||||||
.state('features', {
|
.state('features', {
|
||||||
url: '/features',
|
url: '/features',
|
||||||
templateUrl: 'app/settings/views/settingsFeatures.html',
|
template: require('./settings/views/settingsFeatures.html'),
|
||||||
controller: 'settingsFeaturesController',
|
controller: 'settingsFeaturesController',
|
||||||
data: { authorize: true },
|
data: { authorize: true },
|
||||||
params: { animation: null }
|
params: { animation: null }
|
||||||
})
|
})
|
||||||
.state('help', {
|
.state('help', {
|
||||||
url: '/help',
|
url: '/help',
|
||||||
templateUrl: 'app/settings/views/settingsHelp.html',
|
template: require('./settings/views/settingsHelp.html'),
|
||||||
controller: 'settingsHelpController',
|
controller: 'settingsHelpController',
|
||||||
data: { authorize: true },
|
data: { authorize: true },
|
||||||
params: { animation: null }
|
params: { animation: null }
|
||||||
})
|
})
|
||||||
.state('sync', {
|
.state('sync', {
|
||||||
url: '/sync',
|
url: '/sync',
|
||||||
templateUrl: 'app/settings/views/settingsSync.html',
|
template: require('./settings/views/settingsSync.html'),
|
||||||
controller: 'settingsSyncController',
|
controller: 'settingsSyncController',
|
||||||
data: { authorize: true },
|
data: { authorize: true },
|
||||||
params: { animation: null }
|
params: { animation: null }
|
||||||
})
|
})
|
||||||
.state('premium', {
|
.state('premium', {
|
||||||
url: '/premium',
|
url: '/premium',
|
||||||
templateUrl: 'app/settings/views/settingsPremium.html',
|
template: require('./settings/views/settingsPremium.html'),
|
||||||
controller: 'settingsPremiumController',
|
controller: 'settingsPremiumController',
|
||||||
data: { authorize: true },
|
data: { authorize: true },
|
||||||
params: { animation: null }
|
params: { animation: null }
|
||||||
@ -231,54 +231,60 @@
|
|||||||
|
|
||||||
.state('folders', {
|
.state('folders', {
|
||||||
url: '/folders',
|
url: '/folders',
|
||||||
templateUrl: 'app/settings/views/settingsFolders.html',
|
template: require('./settings/views/settingsFolders.html'),
|
||||||
controller: 'settingsFoldersController',
|
controller: 'settingsFoldersController',
|
||||||
data: { authorize: true },
|
data: { authorize: true },
|
||||||
params: { animation: null }
|
params: { animation: null }
|
||||||
})
|
})
|
||||||
.state('addFolder', {
|
.state('addFolder', {
|
||||||
url: '/addFolder',
|
url: '/addFolder',
|
||||||
templateUrl: 'app/settings/views/settingsAddFolder.html',
|
template: require('./settings/views/settingsAddFolder.html'),
|
||||||
controller: 'settingsAddFolderController',
|
controller: 'settingsAddFolderController',
|
||||||
data: { authorize: true },
|
data: { authorize: true },
|
||||||
params: { animation: null }
|
params: { animation: null }
|
||||||
})
|
})
|
||||||
.state('editFolder', {
|
.state('editFolder', {
|
||||||
url: '/editFolder?folderId',
|
url: '/editFolder?folderId',
|
||||||
templateUrl: 'app/settings/views/settingsEditFolder.html',
|
template: require('./settings/views/settingsEditFolder.html'),
|
||||||
controller: 'settingsEditFolderController',
|
controller: 'settingsEditFolderController',
|
||||||
data: { authorize: true },
|
data: { authorize: true },
|
||||||
params: { animation: null }
|
params: { animation: null }
|
||||||
})
|
})
|
||||||
.state('environment', {
|
.state('environment', {
|
||||||
url: '/environment',
|
url: '/environment',
|
||||||
templateUrl: 'app/settings/views/settingsEnvironment.html',
|
template: require('./settings/views/settingsEnvironment.html'),
|
||||||
controller: 'settingsEnvironmentController',
|
controller: 'settingsEnvironmentController',
|
||||||
data: { authorize: false },
|
data: { authorize: false },
|
||||||
params: { animation: null }
|
params: { animation: null }
|
||||||
})
|
})
|
||||||
.state('lock', {
|
.state('lock', {
|
||||||
url: '/lock',
|
url: '/lock',
|
||||||
templateUrl: 'app/lock/views/lock.html',
|
component: 'lock',
|
||||||
controller: 'lockController',
|
|
||||||
data: { authorize: true },
|
data: { authorize: true },
|
||||||
params: { animation: null }
|
params: { animation: null }
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.run(function ($rootScope, userService, $state, constantsService, stateService) {
|
.run(function ($trace, $transitions, userService, $state, constantsService, stateService) {
|
||||||
|
//$trace.enable('TRANSITION');
|
||||||
|
|
||||||
stateService.init();
|
stateService.init();
|
||||||
|
|
||||||
$rootScope.$on('$stateChangeStart', function (event, toState, toParams) {
|
$transitions.onStart({}, function (trans) {
|
||||||
|
const $state = trans.router.stateService;
|
||||||
|
const toState = trans.to();
|
||||||
|
|
||||||
if ($state.current.name.indexOf('tabs.') > -1 && toState.name.indexOf('tabs.') > -1) {
|
if ($state.current.name.indexOf('tabs.') > -1 && toState.name.indexOf('tabs.') > -1) {
|
||||||
stateService.removeState('vault');
|
stateService.removeState('vault');
|
||||||
stateService.removeState('viewFolder');
|
stateService.removeState('viewFolder');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const userService = trans.injector().get('userService');
|
||||||
|
|
||||||
if (!userService) {
|
if (!userService) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
userService.isAuthenticated(function (isAuthenticated) {
|
userService.isAuthenticated().then((isAuthenticated) => {
|
||||||
if (isAuthenticated) {
|
if (isAuthenticated) {
|
||||||
var obj = {};
|
var obj = {};
|
||||||
obj[constantsService.lastActiveKey] = (new Date()).getTime();
|
obj[constantsService.lastActiveKey] = (new Date()).getTime();
|
||||||
|
@ -14,7 +14,7 @@ angular
|
|||||||
$scope.otherCiphers = [];
|
$scope.otherCiphers = [];
|
||||||
$scope.loaded = false;
|
$scope.loaded = false;
|
||||||
$scope.searchText = null;
|
$scope.searchText = null;
|
||||||
$('#search').focus();
|
document.getElementById('search').focus();
|
||||||
|
|
||||||
$scope.$on('$viewContentLoaded', function () {
|
$scope.$on('$viewContentLoaded', function () {
|
||||||
$timeout(loadVault, 100);
|
$timeout(loadVault, 100);
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
angular
|
angular
|
||||||
.module('bit.directives')
|
.module('bit.directives')
|
||||||
|
|
||||||
.directive('fallbackSrc', function () {
|
.directive('fallbackSrc', function () {
|
||||||
return function (scope, element, attrs) {
|
return function (scope, element, attrs) {
|
||||||
var el = $(element);
|
element[0].addEventListener('error', function (e) {
|
||||||
el.bind('error', function (event) {
|
e.target.src = attrs.fallbackSrc;
|
||||||
el.attr('src', attrs.fallbackSrc);
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
angular
|
angular
|
||||||
.module('bit.directives')
|
.module('bit.directives')
|
||||||
|
|
||||||
// ref: https://stackoverflow.com/a/14165848/1090359
|
// ref: https://stackoverflow.com/a/14165848/1090359
|
||||||
.directive('stopClick', function () {
|
.directive('stopClick', function () {
|
||||||
return function (scope, element, attrs) {
|
return function (scope, element, attrs) {
|
||||||
$(element).click(function (event) {
|
element[0].addEventListener('click', function (e) {
|
||||||
event.preventDefault();
|
e.preventDefault();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
angular
|
angular
|
||||||
.module('bit.directives')
|
.module('bit.directives')
|
||||||
|
|
||||||
.directive('stopProp', function () {
|
.directive('stopProp', function () {
|
||||||
return function (scope, element, attrs) {
|
return function (scope, element, attrs) {
|
||||||
$(element).click(function (event) {
|
element[0].addEventListener('click', function (e) {
|
||||||
event.stopPropagation();
|
e.stopPropagation();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<a ui-sref="environment({animation: 'in-slide-up'})" class="settings-icon">
|
<a ui-sref="environment({animation: 'in-slide-up'})" class="settings-icon">
|
||||||
<i class="fa fa-cog fa-lg"></i><span> Settings</span>
|
<i class="fa fa-cog fa-lg"></i><span> Settings</span>
|
||||||
</a>
|
</a>
|
||||||
<img src="../../../../images/logo@2x.png" alt="bitwarden" />
|
<img src="../../../images/logo@2x.png" alt="bitwarden" />
|
||||||
<p>{{i18n.loginOrCreateNewAccount}}</p>
|
<p>{{i18n.loginOrCreateNewAccount}}</p>
|
||||||
<div class="bottom-buttons">
|
<div class="bottom-buttons">
|
||||||
<a class="btn btn-lg btn-primary btn-block" ui-sref="register({animation: 'in-slide-up'})"
|
<a class="btn btn-lg btn-primary btn-block" ui-sref="register({animation: 'in-slide-up'})"
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
angular
|
angular
|
||||||
.module('bit.global')
|
.module('bit.global')
|
||||||
|
|
||||||
.controller('mainController', function ($scope, $state, authService, toastr, i18nService, $analytics, utilsService,
|
.controller('mainController', function ($scope, $transitions, $state, authService, toastr, i18nService, $analytics, utilsService,
|
||||||
$window) {
|
$window) {
|
||||||
var self = this;
|
var self = this;
|
||||||
self.currentYear = new Date().getFullYear();
|
self.currentYear = new Date().getFullYear();
|
||||||
@ -11,12 +11,13 @@ angular
|
|||||||
self.disableSearch = utilsService && utilsService.isEdge();
|
self.disableSearch = utilsService && utilsService.isEdge();
|
||||||
self.inSidebar = utilsService && utilsService.inSidebar($window);
|
self.inSidebar = utilsService && utilsService.inSidebar($window);
|
||||||
|
|
||||||
$scope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState, fromParams) {
|
$transitions.onSuccess({}, function(transition) {
|
||||||
|
const toParams = transition.params("to");
|
||||||
|
|
||||||
if (toParams.animation) {
|
if (toParams.animation) {
|
||||||
self.animation = toParams.animation;
|
self.animation = toParams.animation;
|
||||||
return;
|
return;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
self.animation = '';
|
self.animation = '';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -42,11 +43,12 @@ angular
|
|||||||
href = hrefParts[0] + '?uilocation=popout' + (hrefParts.length > 0 ? '#' + hrefParts[1] : '');
|
href = hrefParts[0] + '?uilocation=popout' + (hrefParts.length > 0 ? '#' + hrefParts[1] : '');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var bodyRect = document.querySelector('body').getBoundingClientRect();
|
||||||
chrome.windows.create({
|
chrome.windows.create({
|
||||||
url: href,
|
url: href,
|
||||||
type: 'popup',
|
type: 'popup',
|
||||||
width: $('body').width() + 60,
|
width: bodyRect.width + 60,
|
||||||
height: $('body').height()
|
height: bodyRect.height
|
||||||
});
|
});
|
||||||
|
|
||||||
if (utilsService.inPopup($window)) {
|
if (utilsService.inPopup($window)) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="splash-page">
|
<div class="splash-page">
|
||||||
<img src="../../../../images/logo@3x.png" alt="bitwarden" />
|
<img src="../../../images/logo@3x.png" alt="bitwarden" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<form name="theForm" ng-submit="submit()" bit-form="submitPromise">
|
<form name="theForm" ng-submit="$ctrl.submit()" bit-form="submitPromise">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<button type="submit" class="btn btn-link">{{i18n.submit}}</button>
|
<button type="submit" class="btn btn-link">{{$ctrl.i18n.submit}}</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="title">{{i18n.verifyMasterPassword}}</div>
|
<div class="title">{{$ctrl.i18n.verifyMasterPassword}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="list">
|
<div class="list">
|
||||||
@ -11,15 +11,15 @@
|
|||||||
<div class="list-section-items">
|
<div class="list-section-items">
|
||||||
<div class="list-section-item list-section-item-icon-input">
|
<div class="list-section-item list-section-item-icon-input">
|
||||||
<i class="fa fa-lock fa-lg fa-fw"></i>
|
<i class="fa fa-lock fa-lg fa-fw"></i>
|
||||||
<label for="master-password" class="sr-only">{{i18n.masterPass}}</label>
|
<label for="master-password" class="sr-only">{{$ctrl.i18n.masterPass}}</label>
|
||||||
<input id="master-password" type="password" name="MasterPassword" placeholder="{{i18n.masterPass}}"
|
<input id="master-password" type="password" name="MasterPassword" placeholder="{{$ctrl.i18n.masterPass}}"
|
||||||
ng-model="masterPassword">
|
ng-model="masterPassword">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-center text-accent">
|
<p class="text-center text-accent">
|
||||||
<a ng-click="logOut()" href="">{{i18n.logOut}}</a>
|
<a ng-click="$ctrl.logOut()" href="">{{$ctrl.i18n.logOut}}</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
53
src/popup/app/lock/lock.component.ts
Normal file
53
src/popup/app/lock/lock.component.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import CryptoService from '../../../services/crypto.service';
|
||||||
|
import UserService from '../../../services/user.service';
|
||||||
|
|
||||||
|
import * as template from './lock.component.html';
|
||||||
|
|
||||||
|
class LockController {
|
||||||
|
i18n: any;
|
||||||
|
|
||||||
|
constructor(public $scope: any, public $state: any, public i18nService: any,
|
||||||
|
public cryptoService: CryptoService, public toastr: any, public userService: UserService,
|
||||||
|
public SweetAlert: any, public $timeout: any) {
|
||||||
|
this.i18n = i18nService;
|
||||||
|
|
||||||
|
$timeout(() => {
|
||||||
|
document.getElementById('master-password').focus();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
logOut() {
|
||||||
|
this.SweetAlert.swal({
|
||||||
|
title: this.i18nService.logOut,
|
||||||
|
text: this.i18nService.logOutConfirmation,
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonText: this.i18nService.yes,
|
||||||
|
cancelButtonText: this.i18nService.cancel,
|
||||||
|
}, (confirmed: boolean) => {
|
||||||
|
if (confirmed) {
|
||||||
|
chrome.runtime.sendMessage({ command: 'logout' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async submit() {
|
||||||
|
const email = await this.userService.getEmail();
|
||||||
|
const key = this.cryptoService.makeKey(this.$scope.masterPassword, email);
|
||||||
|
const keyHash = await this.cryptoService.hashPassword(this.$scope.masterPassword, key);
|
||||||
|
const storedKeyHash = await this.cryptoService.getKeyHash();
|
||||||
|
|
||||||
|
if (storedKeyHash && keyHash && storedKeyHash === keyHash) {
|
||||||
|
await this.cryptoService.setKey(key);
|
||||||
|
chrome.runtime.sendMessage({ command: 'unlocked' });
|
||||||
|
this.$state.go('tabs.current');
|
||||||
|
} else {
|
||||||
|
this.toastr.error(this.i18nService.invalidMasterPassword, this.i18nService.errorsOccurred);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const LockComponent = {
|
||||||
|
bindings: {},
|
||||||
|
controller: LockController,
|
||||||
|
template,
|
||||||
|
};
|
9
src/popup/app/lock/lock.module.ts
Normal file
9
src/popup/app/lock/lock.module.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import * as angular from 'angular';
|
||||||
|
import { LockComponent } from './lock.component';
|
||||||
|
|
||||||
|
export default angular
|
||||||
|
.module('bit.lock', ['ngAnimate', 'toastr'])
|
||||||
|
|
||||||
|
.component('lock', LockComponent)
|
||||||
|
|
||||||
|
.name;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user