mirror of
https://github.com/bitwarden/web
synced 2025-12-12 14:23:18 +00:00
Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
264759cfa0 | ||
|
|
b5d265526a | ||
|
|
22290eafb8 | ||
|
|
3101e57c36 | ||
|
|
b72a52232d | ||
|
|
a5b8e703fc | ||
|
|
fb26425f17 | ||
|
|
3114e20aef | ||
|
|
a52d2f4b7a | ||
|
|
34e484c377 | ||
|
|
08e8e9ff64 | ||
|
|
ebf55390eb | ||
|
|
c328144a58 | ||
|
|
4b583bea9b | ||
|
|
3f0ca412c6 | ||
|
|
0050b570b4 | ||
|
|
9405be03b0 | ||
|
|
b5b706fe06 | ||
|
|
8313d9fa90 | ||
|
|
93b96b3be7 | ||
|
|
50e6818f2b | ||
|
|
104fb57bd8 | ||
|
|
7ba6b2f00a | ||
|
|
d8e8939eca | ||
|
|
26c5f4049d | ||
|
|
b6c9dba0fc | ||
|
|
8badc1a354 |
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<configuration>
|
|
||||||
<packageSources>
|
|
||||||
<!--To inherit the global NuGet package sources remove the <clear/> line below -->
|
|
||||||
<clear />
|
|
||||||
<add key="api.nuget.org" value="https://api.nuget.org/v3/index.json" />
|
|
||||||
</packageSources>
|
|
||||||
</configuration>
|
|
||||||
19
README.md
19
README.md
@@ -1,9 +1,26 @@
|
|||||||
[](https://gitter.im/bitwarden/Lobby)
|
[] (https://ci.appveyor.com/project/bitwarden/web) [](https://gitter.im/bitwarden/Lobby)
|
||||||
|
|
||||||
# bitwarden Web
|
# bitwarden Web
|
||||||
|
|
||||||
The bitwarden Web project is an AngularJS application that powers the web vault (https://vault.bitwarden.com/).
|
The bitwarden Web project is an AngularJS application that powers the web vault (https://vault.bitwarden.com/).
|
||||||
|
|
||||||
|
# Build/Run
|
||||||
|
|
||||||
|
**Requirements**
|
||||||
|
|
||||||
|
- Node.js
|
||||||
|
- Gulp
|
||||||
|
|
||||||
|
Unless you are running the [Core](https://github.com/bitwarden/core) API locally, you'll probably need to switch the
|
||||||
|
application to target the production API. Open `package.json` and set `production` to `true`.
|
||||||
|
|
||||||
|
Then run the following commands:
|
||||||
|
|
||||||
|
- `gulp build`
|
||||||
|
- `gulp serve`
|
||||||
|
|
||||||
|
You can now access the web vault at `http://localhost:4001`.
|
||||||
|
|
||||||
# Contribute
|
# Contribute
|
||||||
|
|
||||||
Code contributions are welcome! Please commit any pull requests against the `master` branch.
|
Code contributions are welcome! Please commit any pull requests against the `master` branch.
|
||||||
|
|||||||
@@ -3,34 +3,37 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
|||||||
# Visual Studio 14
|
# Visual Studio 14
|
||||||
VisualStudioVersion = 14.0.25420.1
|
VisualStudioVersion = 14.0.25420.1
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{860863C9-0436-43D4-840D-FE919C9F6FFC}"
|
Project("{E24C65DC-7377-472B-9ABA-BC803B73C61A}") = "bitwarden-web", ".", "{25BEDEF4-2CAF-445A-807D-63C17FF85694}"
|
||||||
EndProject
|
ProjectSection(WebsiteProperties) = preProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{14FE7221-D377-4AD5-9A9E-4541577CF05A}"
|
TargetFrameworkMoniker = ".NETFramework,Version%3Dv4.6.1"
|
||||||
ProjectSection(SolutionItems) = preProject
|
Debug.AspNetCompiler.VirtualPath = "/localhost_15509"
|
||||||
.gitignore = .gitignore
|
Debug.AspNetCompiler.PhysicalPath = "."
|
||||||
CNAME = CNAME
|
Debug.AspNetCompiler.TargetPath = "PrecompiledWeb\localhost_15509\"
|
||||||
global.json = global.json
|
Debug.AspNetCompiler.Updateable = "true"
|
||||||
NuGet.Config = NuGet.Config
|
Debug.AspNetCompiler.ForceOverwrite = "true"
|
||||||
README.md = README.md
|
Debug.AspNetCompiler.FixedNames = "false"
|
||||||
|
Debug.AspNetCompiler.Debug = "True"
|
||||||
|
Release.AspNetCompiler.VirtualPath = "/localhost_15509"
|
||||||
|
Release.AspNetCompiler.PhysicalPath = "."
|
||||||
|
Release.AspNetCompiler.TargetPath = "PrecompiledWeb\localhost_15509\"
|
||||||
|
Release.AspNetCompiler.Updateable = "true"
|
||||||
|
Release.AspNetCompiler.ForceOverwrite = "true"
|
||||||
|
Release.AspNetCompiler.FixedNames = "false"
|
||||||
|
Release.AspNetCompiler.Debug = "False"
|
||||||
|
VWDPort = "15509"
|
||||||
|
SlnRelativePath = "."
|
||||||
|
DefaultWebSiteLanguage = "Visual C#"
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Web", "src\Web\Web.xproj", "{0BEBF47C-BA0B-48AC-B48C-718F94084AD5}"
|
|
||||||
EndProject
|
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
Release|Any CPU = Release|Any CPU
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{0BEBF47C-BA0B-48AC-B48C-718F94084AD5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{25BEDEF4-2CAF-445A-807D-63C17FF85694}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{0BEBF47C-BA0B-48AC-B48C-718F94084AD5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{25BEDEF4-2CAF-445A-807D-63C17FF85694}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{0BEBF47C-BA0B-48AC-B48C-718F94084AD5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{0BEBF47C-BA0B-48AC-B48C-718F94084AD5}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(NestedProjects) = preSolution
|
|
||||||
{0BEBF47C-BA0B-48AC-B48C-718F94084AD5} = {860863C9-0436-43D4-840D-FE919C9F6FFC}
|
|
||||||
EndGlobalSection
|
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"projects": [ "src", "test" ],
|
|
||||||
"sdk": {
|
|
||||||
"version": "1.0.0-preview2-003121"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,25 +8,26 @@ var gulp = require('gulp'),
|
|||||||
uglify = require('gulp-uglify'),
|
uglify = require('gulp-uglify'),
|
||||||
ghPages = require('gulp-gh-pages'),
|
ghPages = require('gulp-gh-pages'),
|
||||||
less = require('gulp-less'),
|
less = require('gulp-less'),
|
||||||
|
connect = require('gulp-connect'),
|
||||||
ngAnnotate = require('gulp-ng-annotate'),
|
ngAnnotate = require('gulp-ng-annotate'),
|
||||||
preprocess = require('gulp-preprocess'),
|
preprocess = require('gulp-preprocess'),
|
||||||
runSequence = require('run-sequence'),
|
runSequence = require('run-sequence'),
|
||||||
merge = require('merge-stream'),
|
merge = require('merge-stream'),
|
||||||
ngConfig = require('gulp-ng-config'),
|
ngConfig = require('gulp-ng-config'),
|
||||||
settings = require('./settings.json'),
|
settings = require('./settings.json'),
|
||||||
project = require('./project.json'),
|
project = require('./package.json'),
|
||||||
jshint = require('gulp-jshint'),
|
jshint = require('gulp-jshint'),
|
||||||
_ = require('lodash');
|
_ = require('lodash');
|
||||||
|
|
||||||
var paths = {};
|
var paths = {};
|
||||||
paths.dist = '../../dist/';
|
paths.dist = './dist/';
|
||||||
paths.webroot = './wwwroot/'
|
paths.webroot = './src/'
|
||||||
paths.js = paths.webroot + 'js/**/*.js';
|
paths.js = paths.webroot + 'js/**/*.js';
|
||||||
paths.minJs = paths.webroot + 'js/**/*.min.js';
|
paths.minJs = paths.webroot + 'js/**/*.min.js';
|
||||||
paths.concatJsDest = paths.webroot + 'js/bw.min.js';
|
paths.concatJsDest = paths.webroot + 'js/bw.min.js';
|
||||||
paths.libDir = paths.webroot + 'lib/';
|
paths.libDir = paths.webroot + 'lib/';
|
||||||
paths.npmDir = 'node_modules/';
|
paths.npmDir = 'node_modules/';
|
||||||
paths.lessDir = 'less/';
|
paths.lessDir = paths.webroot + 'less/';
|
||||||
paths.cssDir = paths.webroot + 'css/';
|
paths.cssDir = paths.webroot + 'css/';
|
||||||
paths.jsDir = paths.webroot + 'js/';
|
paths.jsDir = paths.webroot + 'js/';
|
||||||
|
|
||||||
@@ -189,9 +190,9 @@ function config() {
|
|||||||
constants: _.merge({}, {
|
constants: _.merge({}, {
|
||||||
appSettings: {
|
appSettings: {
|
||||||
version: project.version,
|
version: project.version,
|
||||||
environment: project.environment
|
environment: project.production ? 'Production' : 'Development'
|
||||||
}
|
}
|
||||||
}, require('./settings.' + project.environment + '.json') || {})
|
}, require('./settings' + (project.production ? '.Production' : '') + '.json') || {})
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,7 +214,7 @@ gulp.task('dist:clean', function (cb) {
|
|||||||
gulp.task('dist:move', function () {
|
gulp.task('dist:move', function () {
|
||||||
var moves = [
|
var moves = [
|
||||||
{
|
{
|
||||||
src: '../../CNAME',
|
src: './CNAME',
|
||||||
dest: paths.dist
|
dest: paths.dist
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -324,3 +325,10 @@ gulp.task('deploy', ['dist'], function () {
|
|||||||
return gulp.src(paths.dist + '**/*')
|
return gulp.src(paths.dist + '**/*')
|
||||||
.pipe(ghPages({ cacheDir: paths.dist + '.publish' }));
|
.pipe(ghPages({ cacheDir: paths.dist + '.publish' }));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
gulp.task('serve', function () {
|
||||||
|
connect.server({
|
||||||
|
port: 4001,
|
||||||
|
root: ['src']
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "bitwarden",
|
"name": "bitwarden",
|
||||||
"version": "0.0.0",
|
"version": "1.5.0",
|
||||||
|
"production": false,
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"connect": "3.4.1",
|
"connect": "3.4.1",
|
||||||
"lodash": "4.13.1",
|
"lodash": "4.13.1",
|
||||||
@@ -14,6 +15,7 @@
|
|||||||
"gulp-preprocess": "2.0.0",
|
"gulp-preprocess": "2.0.0",
|
||||||
"gulp-ng-annotate": "2.0.0",
|
"gulp-ng-annotate": "2.0.0",
|
||||||
"gulp-ng-config": "1.3.1",
|
"gulp-ng-config": "1.3.1",
|
||||||
|
"gulp-connect": "5.0.0",
|
||||||
"jshint": "2.9.2",
|
"jshint": "2.9.2",
|
||||||
"gulp-jshint": "2.0.1",
|
"gulp-jshint": "2.0.1",
|
||||||
"rimraf": "2.5.2",
|
"rimraf": "2.5.2",
|
||||||
6
settings.json
Normal file
6
settings.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"appSettings": {
|
||||||
|
"rememberedEmailCookieName": "bit.rememberedEmail",
|
||||||
|
"apiUri": "http://localhost:4000"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
using System.IO;
|
|
||||||
using Microsoft.AspNetCore.Hosting;
|
|
||||||
|
|
||||||
namespace Bit.Web
|
|
||||||
{
|
|
||||||
public class Program
|
|
||||||
{
|
|
||||||
public static void Main(string[] args)
|
|
||||||
{
|
|
||||||
var host = new WebHostBuilder()
|
|
||||||
.UseKestrel()
|
|
||||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
|
||||||
.UseIISIntegration()
|
|
||||||
.UseStartup<Startup>()
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
host.Run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
using System.Reflection;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
|
||||||
// set of attributes. Change these attribute values to modify the information
|
|
||||||
// associated with an assembly.
|
|
||||||
[assembly: AssemblyTitle("Bit.Web")]
|
|
||||||
[assembly: AssemblyDescription("")]
|
|
||||||
[assembly: AssemblyConfiguration("")]
|
|
||||||
[assembly: AssemblyCompany("bitwarden Web")]
|
|
||||||
[assembly: AssemblyProduct("bitwarden Web")]
|
|
||||||
[assembly: AssemblyCopyright("Copyright © 2016")]
|
|
||||||
[assembly: AssemblyTrademark("")]
|
|
||||||
[assembly: AssemblyCulture("")]
|
|
||||||
|
|
||||||
// Setting ComVisible to false makes the types in this assembly not visible
|
|
||||||
// to COM components. If you need to access a type in this assembly from
|
|
||||||
// COM, set the ComVisible attribute to true on that type.
|
|
||||||
[assembly: ComVisible(false)]
|
|
||||||
|
|
||||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
|
||||||
[assembly: Guid("0bebf47c-ba0b-48ac-b48c-718f94084ad5")]
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"iisSettings": {
|
|
||||||
"windowsAuthentication": false,
|
|
||||||
"anonymousAuthentication": true,
|
|
||||||
"iisExpress": {
|
|
||||||
"applicationUrl": "http://localhost:4001/",
|
|
||||||
"sslPort": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"profiles": {
|
|
||||||
"IIS Express": {
|
|
||||||
"commandName": "IISExpress",
|
|
||||||
"launchBrowser": true,
|
|
||||||
"environmentVariables": {
|
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Web": {
|
|
||||||
"commandName": "Project",
|
|
||||||
"launchBrowser": true,
|
|
||||||
"launchUrl": "http://localhost:5001",
|
|
||||||
"environmentVariables": {
|
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Microsoft.AspNetCore.Builder;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
|
|
||||||
namespace Bit.Web
|
|
||||||
{
|
|
||||||
public class Startup
|
|
||||||
{
|
|
||||||
public void ConfigureServices(IServiceCollection services) { }
|
|
||||||
|
|
||||||
public void Configure(IApplicationBuilder app)
|
|
||||||
{
|
|
||||||
app.UseFileServer();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<PropertyGroup>
|
|
||||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
|
||||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
|
||||||
</PropertyGroup>
|
|
||||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
|
||||||
<PropertyGroup Label="Globals">
|
|
||||||
<ProjectGuid>0bebf47c-ba0b-48ac-b48c-718f94084ad5</ProjectGuid>
|
|
||||||
<RootNamespace>Bit.Vault</RootNamespace>
|
|
||||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
|
|
||||||
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
|
|
||||||
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup>
|
|
||||||
<SchemaVersion>2.0</SchemaVersion>
|
|
||||||
<DevelopmentServerPort>4001</DevelopmentServerPort>
|
|
||||||
</PropertyGroup>
|
|
||||||
<Import Project="$(VSToolsPath)\DotNet.Web\Microsoft.DotNet.Web.targets" Condition="'$(VSToolsPath)' != ''" />
|
|
||||||
</Project>
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
@import url(https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700,300italic,400italic,600italic);
|
|
||||||
@import "../node_modules/toastr/toastr.less";
|
|
||||||
|
|
||||||
/* Start AdminLTE */
|
|
||||||
|
|
||||||
//Bootstrap Variables & Mixins
|
|
||||||
//The core bootstrap code have not been modified. These files
|
|
||||||
//are included only for reference.
|
|
||||||
@import (reference) "../node_modules/admin-lte/build/bootstrap-less/mixins.less";
|
|
||||||
@import (reference) "../node_modules/admin-lte/build/bootstrap-less/variables.less";
|
|
||||||
//MISC
|
|
||||||
//----
|
|
||||||
@import "../node_modules/admin-lte/build/less/core.less";
|
|
||||||
@import "../node_modules/admin-lte/build/less/variables.less";
|
|
||||||
@import "../node_modules/admin-lte/build/less/mixins.less";
|
|
||||||
//COMPONENTS
|
|
||||||
//-----------
|
|
||||||
@import "../node_modules/admin-lte/build/less/header.less";
|
|
||||||
@import "../node_modules/admin-lte/build/less/sidebar.less";
|
|
||||||
@import "../node_modules/admin-lte/build/less/sidebar-mini.less";
|
|
||||||
@import "../node_modules/admin-lte/build/less/control-sidebar.less";
|
|
||||||
@import "../node_modules/admin-lte/build/less/dropdown.less";
|
|
||||||
@import "../node_modules/admin-lte/build/less/forms.less";
|
|
||||||
@import "../node_modules/admin-lte/build/less/progress-bars.less";
|
|
||||||
@import "../node_modules/admin-lte/build/less/small-box.less";
|
|
||||||
@import "../node_modules/admin-lte/build/less/boxes.less";
|
|
||||||
@import "../node_modules/admin-lte/build/less/info-box.less";
|
|
||||||
@import "../node_modules/admin-lte/build/less/timeline.less";
|
|
||||||
@import "../node_modules/admin-lte/build/less/buttons.less";
|
|
||||||
@import "../node_modules/admin-lte/build/less/callout.less";
|
|
||||||
@import "../node_modules/admin-lte/build/less/alerts.less";
|
|
||||||
@import "../node_modules/admin-lte/build/less/navs.less";
|
|
||||||
@import "../node_modules/admin-lte/build/less/table.less";
|
|
||||||
@import "../node_modules/admin-lte/build/less/labels.less";
|
|
||||||
@import "../node_modules/admin-lte/build/less/modal.less";
|
|
||||||
//PAGES
|
|
||||||
//------
|
|
||||||
@import "../node_modules/admin-lte/build/less/login_and_register.less";
|
|
||||||
@import "../node_modules/admin-lte/build/less/404_500_errors.less";
|
|
||||||
//Miscellaneous
|
|
||||||
//-------------
|
|
||||||
@import "../node_modules/admin-lte/build/less/miscellaneous.less";
|
|
||||||
@import "../node_modules/admin-lte/build/less/print.less";
|
|
||||||
|
|
||||||
/* End AdminLTE */
|
|
||||||
|
|
||||||
@import "../node_modules/admin-lte/build/less/skins/skin-blue.less";
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
{
|
|
||||||
"version": "1.2.2",
|
|
||||||
"environment": "Development",
|
|
||||||
|
|
||||||
"dependencies": {
|
|
||||||
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
|
|
||||||
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
|
|
||||||
"Microsoft.AspNetCore.StaticFiles": "1.0.0"
|
|
||||||
},
|
|
||||||
|
|
||||||
"tools": {
|
|
||||||
"Microsoft.AspNetCore.Server.IISIntegration.Tools": {
|
|
||||||
"version": "1.0.0-preview2-final",
|
|
||||||
"imports": "portable-net45+win8+dnxcore50"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"frameworks": {
|
|
||||||
"netcoreapp1.0": {
|
|
||||||
"dependencies": {
|
|
||||||
"Microsoft.NETCore.App": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"type": "platform"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"buildOptions": {
|
|
||||||
"emitEntryPoint": true,
|
|
||||||
"preserveCompilationContext": true
|
|
||||||
},
|
|
||||||
|
|
||||||
"runtimeOptions": {
|
|
||||||
"gcServer": false,
|
|
||||||
"gcConcurrent": true
|
|
||||||
},
|
|
||||||
|
|
||||||
"publishOptions": {
|
|
||||||
"include": [
|
|
||||||
"wwwroot",
|
|
||||||
"Views",
|
|
||||||
"settings.json",
|
|
||||||
"settings.Development.json",
|
|
||||||
"settings.Production.json",
|
|
||||||
"settings.Staging.json",
|
|
||||||
"web.config"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
"scripts": {
|
|
||||||
"postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
|
|
||||||
},
|
|
||||||
|
|
||||||
"userSecretsId": "aspnet-Vault-20160519103145"
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"appSettings": {
|
|
||||||
"apiUri": "http://localhost:4000"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"appSettings": {
|
|
||||||
"apiUri": "https://api.bitwarden.com"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"appSettings": {
|
|
||||||
"rememberedEmailCookieName": "bit.rememberedEmail"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<configuration>
|
|
||||||
<system.webServer>
|
|
||||||
<handlers>
|
|
||||||
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified"/>
|
|
||||||
</handlers>
|
|
||||||
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false"/>
|
|
||||||
</system.webServer>
|
|
||||||
</configuration>
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
/// <autosync enabled="true" />
|
|
||||||
/// <reference path="../gulpfile.js" />
|
|
||||||
/// <reference path="app/accounts/accountsLoginController.js" />
|
|
||||||
/// <reference path="app/accounts/accountsLogoutController.js" />
|
|
||||||
/// <reference path="app/accounts/accountsmodule.js" />
|
|
||||||
/// <reference path="app/accounts/accountspasswordhintcontroller.js" />
|
|
||||||
/// <reference path="app/accounts/accountsRegisterController.js" />
|
|
||||||
/// <reference path="app/apiInterceptor.js" />
|
|
||||||
/// <reference path="app/app.js" />
|
|
||||||
/// <reference path="app/config.js" />
|
|
||||||
/// <reference path="app/directives/apiFieldDirective.js" />
|
|
||||||
/// <reference path="app/directives/apiFormDirective.js" />
|
|
||||||
/// <reference path="app/directives/directivesModule.js" />
|
|
||||||
/// <reference path="app/directives/masterPasswordDirective.js" />
|
|
||||||
/// <reference path="app/directives/pageTitleDirective.js" />
|
|
||||||
/// <reference path="app/directives/passwordmeterdirective.js" />
|
|
||||||
/// <reference path="app/directives/passwordviewerdirective.js" />
|
|
||||||
/// <reference path="app/global/globalModule.js" />
|
|
||||||
/// <reference path="app/global/mainController.js" />
|
|
||||||
/// <reference path="app/global/sideNavController.js" />
|
|
||||||
/// <reference path="app/global/topNavController.js" />
|
|
||||||
/// <reference path="app/services/apiService.js" />
|
|
||||||
/// <reference path="app/services/authService.js" />
|
|
||||||
/// <reference path="app/services/cipherService.js" />
|
|
||||||
/// <reference path="app/services/cryptoService.js" />
|
|
||||||
/// <reference path="app/services/importservice.js" />
|
|
||||||
/// <reference path="app/services/passwordservice.js" />
|
|
||||||
/// <reference path="app/services/servicesModule.js" />
|
|
||||||
/// <reference path="app/services/tokenService.js" />
|
|
||||||
/// <reference path="app/services/validationservice.js" />
|
|
||||||
/// <reference path="app/settings.js" />
|
|
||||||
/// <reference path="app/settings/settingsChangeEmailController.js" />
|
|
||||||
/// <reference path="app/settings/settingsChangePasswordController.js" />
|
|
||||||
/// <reference path="app/settings/settingsController.js" />
|
|
||||||
/// <reference path="app/settings/settingsdeletecontroller.js" />
|
|
||||||
/// <reference path="app/settings/settingsmodule.js" />
|
|
||||||
/// <reference path="app/settings/settingsSessionsController.js" />
|
|
||||||
/// <reference path="app/settings/settingsTwoFactorController.js" />
|
|
||||||
/// <reference path="app/tools/toolsAuditsController.js" />
|
|
||||||
/// <reference path="app/tools/toolsController.js" />
|
|
||||||
/// <reference path="app/tools/toolsExportController.js" />
|
|
||||||
/// <reference path="app/tools/toolsImportController.js" />
|
|
||||||
/// <reference path="app/tools/toolsmodule.js" />
|
|
||||||
/// <reference path="app/vault/vaultAddFolderController.js" />
|
|
||||||
/// <reference path="app/vault/vaultAddSiteController.js" />
|
|
||||||
/// <reference path="app/vault/vaultController.js" />
|
|
||||||
/// <reference path="app/vault/vaultEditFolderController.js" />
|
|
||||||
/// <reference path="app/vault/vaultEditSiteController.js" />
|
|
||||||
/// <reference path="app/vault/vaultmodule.js" />
|
|
||||||
/// <reference path="lib/admin-lte/js/app.js" />
|
|
||||||
/// <reference path="lib/angular/angular.js" />
|
|
||||||
/// <reference path="lib/angular-bootstrap/angular-bootstrap-tpls.js" />
|
|
||||||
/// <reference path="lib/angular-bootstrap-show-errors/showErrors.js" />
|
|
||||||
/// <reference path="lib/angular-cookies/angular-cookies.js" />
|
|
||||||
/// <reference path="lib/angular-jwt/angular-jwt.js" />
|
|
||||||
/// <reference path="lib/angular-md5/angular-md5.js" />
|
|
||||||
/// <reference path="lib/angular-messages/angular-messages.js" />
|
|
||||||
/// <reference path="lib/angular-resource/angular-resource.js" />
|
|
||||||
/// <reference path="lib/angulartics/angulartics.js" />
|
|
||||||
/// <reference path="lib/angulartics/angulartics-ga.js" />
|
|
||||||
/// <reference path="lib/angular-toastr/angular-toastr.js" />
|
|
||||||
/// <reference path="lib/angular-toastr/angular-toastr.min.js" />
|
|
||||||
/// <reference path="lib/angular-toastr/angular-toastr.tpls.min.js" />
|
|
||||||
/// <reference path="lib/angular-ui-router/angular-ui-router.js" />
|
|
||||||
/// <reference path="lib/bootstrap/js/bootstrap.min.js" />
|
|
||||||
/// <reference path="lib/clipboard/clipboard.js" />
|
|
||||||
/// <reference path="lib/jquery/jquery.js" />
|
|
||||||
/// <reference path="lib/ngclipboard/ngclipboard.js" />
|
|
||||||
/// <reference path="lib/ngstorage/ngStorage.js" />
|
|
||||||
/// <reference path="lib/papaparse/papaparse.js" />
|
|
||||||
/// <reference path="lib/sjcl/bitArray.js" />
|
|
||||||
/// <reference path="lib/sjcl/cbc.js" />
|
|
||||||
/// <reference path="lib/sjcl/sjcl.js" />
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
angular.module("bit")
|
|
||||||
.constant("appSettings", {"rememberedEmailCookieName":"bit.rememberedEmail","version":"1.2.2","environment":"Development","apiUri":"http://localhost:4000"});
|
|
||||||
21
src/app/accounts/accountsRecoverController.js
Normal file
21
src/app/accounts/accountsRecoverController.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
angular
|
||||||
|
.module('bit.accounts')
|
||||||
|
|
||||||
|
.controller('accountsRecoverController', function ($scope, apiService, cryptoService) {
|
||||||
|
$scope.success = false;
|
||||||
|
|
||||||
|
$scope.submit = function (model) {
|
||||||
|
var email = model.email.toLowerCase();
|
||||||
|
var key = cryptoService.makeKey(model.masterPassword, email);
|
||||||
|
|
||||||
|
var request = {
|
||||||
|
email: email,
|
||||||
|
masterPasswordHash: cryptoService.hashPassword(model.masterPassword, key),
|
||||||
|
recoveryCode: model.code.replace(/\s/g, '').toLowerCase()
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.submitPromise = apiService.accounts.postTwoFactorRecover(request, function () {
|
||||||
|
$scope.success = true;
|
||||||
|
}).$promise;
|
||||||
|
};
|
||||||
|
});
|
||||||
@@ -13,7 +13,10 @@
|
|||||||
<span class="fa fa-lock form-control-feedback"></span>
|
<span class="fa fa-lock form-control-feedback"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-offset-7 col-xs-5">
|
<div class="col-xs-7">
|
||||||
|
<a ui-sref="frontend.recover">Lost authenticator app?</a>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-5">
|
||||||
<button type="submit" class="btn btn-primary btn-block btn-flat" ng-disabled="twoFactorForm.$loading">
|
<button type="submit" class="btn btn-primary btn-block btn-flat" ng-disabled="twoFactorForm.$loading">
|
||||||
<i class="fa fa-refresh fa-spin loading-icon" ng-show="twoFactorForm.$loading"></i>Log In
|
<i class="fa fa-refresh fa-spin loading-icon" ng-show="twoFactorForm.$loading"></i>Log In
|
||||||
</button>
|
</button>
|
||||||
52
src/app/accounts/views/accountsRecover.html
Normal file
52
src/app/accounts/views/accountsRecover.html
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
<div class="login-box">
|
||||||
|
<div class="login-logo">
|
||||||
|
<i class="fa fa-shield"></i> <b>bit</b>warden
|
||||||
|
</div>
|
||||||
|
<div class="login-box-body">
|
||||||
|
<p class="login-box-msg">Lost your authenticator app?</p>
|
||||||
|
<div class="text-center" ng-show="success">
|
||||||
|
<div class="callout callout-success">
|
||||||
|
Two-step login has been successfully disabled on your account.
|
||||||
|
</div>
|
||||||
|
<a ui-sref="frontend.login.info">Ready to log in?</a>
|
||||||
|
</div>
|
||||||
|
<form name="recoverForm" ng-submit="recoverForm.$valid && submit(model)" ng-show="!success"
|
||||||
|
api-form="submitPromise">
|
||||||
|
<div class="callout callout-danger validation-errors" ng-show="recoverForm.$errors">
|
||||||
|
<h4>Errors have occured</h4>
|
||||||
|
<ul>
|
||||||
|
<li ng-repeat="e in recoverForm.$errors">{{e}}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="form-group has-feedback" show-errors>
|
||||||
|
<label for="email" class="sr-only">Email</label>
|
||||||
|
<input type="email" id="email" name="Email" class="form-control" placeholder="Email" ng-model="model.email"
|
||||||
|
required api-field />
|
||||||
|
<span class="fa fa-envelope form-control-feedback"></span>
|
||||||
|
</div>
|
||||||
|
<div class="form-group has-feedback" show-errors>
|
||||||
|
<label for="masterPassword" class="sr-only">Master Password</label>
|
||||||
|
<input type="password" id="masterPassword" name="MasterPasswordHash" class="form-control" placeholder="Master Password"
|
||||||
|
ng-model="model.masterPassword"
|
||||||
|
required api-field />
|
||||||
|
<span class="fa fa-lock form-control-feedback"></span>
|
||||||
|
</div>
|
||||||
|
<div class="form-group has-feedback" show-errors>
|
||||||
|
<label for="code" class="sr-only">Recovery code</label>
|
||||||
|
<input type="text" id="code" name="RecoveryCode" class="form-control" placeholder="Recovery code"
|
||||||
|
ng-model="model.code" required api-field />
|
||||||
|
<span class="fa fa-key form-control-feedback"></span>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-7">
|
||||||
|
<a ui-sref="frontend.login.info">Ready to log in?</a>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-5">
|
||||||
|
<button type="submit" class="btn btn-primary btn-block btn-flat" ng-disabled="recoverForm.$loading">
|
||||||
|
<i class="fa fa-refresh fa-spin loading-icon" ng-show="recoverForm.$loading"></i>Submit
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -105,6 +105,15 @@ angular
|
|||||||
bodyClass: 'login-page'
|
bodyClass: 'login-page'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.state('frontend.recover', {
|
||||||
|
url: '^/recover',
|
||||||
|
templateUrl: 'app/accounts/views/accountsRecover.html',
|
||||||
|
controller: 'accountsRecoverController',
|
||||||
|
data: {
|
||||||
|
pageTitle: 'Recover Account',
|
||||||
|
bodyClass: 'login-page'
|
||||||
|
}
|
||||||
|
})
|
||||||
.state('frontend.register', {
|
.state('frontend.register', {
|
||||||
url: '^/register',
|
url: '^/register',
|
||||||
templateUrl: 'app/accounts/views/accountsRegister.html',
|
templateUrl: 'app/accounts/views/accountsRegister.html',
|
||||||
@@ -38,6 +38,7 @@
|
|||||||
putProfile: { url: _apiUri + '/accounts/profile', method: 'POST', params: {} },
|
putProfile: { url: _apiUri + '/accounts/profile', method: 'POST', params: {} },
|
||||||
getTwoFactor: { url: _apiUri + '/accounts/two-factor', method: 'GET', params: {} },
|
getTwoFactor: { url: _apiUri + '/accounts/two-factor', method: 'GET', params: {} },
|
||||||
putTwoFactor: { url: _apiUri + '/accounts/two-factor', method: 'POST', params: {} },
|
putTwoFactor: { url: _apiUri + '/accounts/two-factor', method: 'POST', params: {} },
|
||||||
|
postTwoFactorRecover: { url: _apiUri + '/accounts/two-factor-recover', method: 'POST', params: {} },
|
||||||
postPasswordHint: { url: _apiUri + '/accounts/password-hint', method: 'POST', params: {} },
|
postPasswordHint: { url: _apiUri + '/accounts/password-hint', method: 'POST', params: {} },
|
||||||
putSecurityStamp: { url: _apiUri + '/accounts/security-stamp', method: 'POST', params: {} },
|
putSecurityStamp: { url: _apiUri + '/accounts/security-stamp', method: 'POST', params: {} },
|
||||||
'import': { url: _apiUri + '/accounts/import', method: 'POST', params: {} },
|
'import': { url: _apiUri + '/accounts/import', method: 'POST', params: {} },
|
||||||
@@ -34,7 +34,7 @@ angular
|
|||||||
|
|
||||||
_service.logInTwoFactor = function (code, provider) {
|
_service.logInTwoFactor = function (code, provider) {
|
||||||
var request = {
|
var request = {
|
||||||
code: code,
|
code: code.replace(' ', ''),
|
||||||
provider: provider
|
provider: provider
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -32,6 +32,21 @@
|
|||||||
case '1password1pif':
|
case '1password1pif':
|
||||||
import1Password1Pif(file, success, error);
|
import1Password1Pif(file, success, error);
|
||||||
break;
|
break;
|
||||||
|
case 'chromecsv':
|
||||||
|
importChromeCsv(file, success, error);
|
||||||
|
break;
|
||||||
|
case 'firefoxpasswordexportercsvxml':
|
||||||
|
importFirefoxPasswordExporterCsvXml(file, success, error);
|
||||||
|
break;
|
||||||
|
case 'upmcsv':
|
||||||
|
importUpmCsv(file, success, error);
|
||||||
|
break;
|
||||||
|
case 'keepercsv':
|
||||||
|
importKeeperCsv(file, success, error);
|
||||||
|
break;
|
||||||
|
case 'passworddragonxml':
|
||||||
|
importPasswordDragonXml(file, success, error);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
error();
|
error();
|
||||||
break;
|
break;
|
||||||
@@ -166,7 +181,8 @@
|
|||||||
function parseData(data) {
|
function parseData(data) {
|
||||||
var folders = [],
|
var folders = [],
|
||||||
sites = [],
|
sites = [],
|
||||||
siteRelationships = [];
|
siteRelationships = [],
|
||||||
|
badDataSites = 0;
|
||||||
|
|
||||||
angular.forEach(data, function (value, key) {
|
angular.forEach(data, function (value, key) {
|
||||||
var folderIndex = folders.length,
|
var folderIndex = folders.length,
|
||||||
@@ -184,6 +200,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((!value.name || value.name === '') && (!value.password || value.password === '')) {
|
||||||
|
badDataSites++;
|
||||||
|
}
|
||||||
|
|
||||||
sites.push({
|
sites.push({
|
||||||
favorite: value.fav === '1',
|
favorite: value.fav === '1',
|
||||||
uri: value.url && value.url !== '' ? trimUri(value.url) : null,
|
uri: value.url && value.url !== '' ? trimUri(value.url) : null,
|
||||||
@@ -208,9 +228,14 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (badDataSites && badDataSites > (data.length / 2)) {
|
||||||
|
error('CSV data is not formatted correctly from LastPass. Please check your import file and try again.');
|
||||||
|
}
|
||||||
|
else {
|
||||||
success(folders, sites, siteRelationships);
|
success(folders, sites, siteRelationships);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function importSafeInCloudCsv(file, success, error) {
|
function importSafeInCloudCsv(file, success, error) {
|
||||||
Papa.parse(file, {
|
Papa.parse(file, {
|
||||||
@@ -556,12 +581,15 @@
|
|||||||
reader.readAsText(file, 'utf-8');
|
reader.readAsText(file, 'utf-8');
|
||||||
reader.onload = function (evt) {
|
reader.onload = function (evt) {
|
||||||
var fileContent = evt.target.result;
|
var fileContent = evt.target.result;
|
||||||
var jsonParts = fileContent.split(/(?:\r\n|\r|\n)\*\*\*.*?\*\*\*(?:\r\n|\r|\n)/);
|
var fileLines = fileContent.split(/(?:\r\n|\r|\n)/);
|
||||||
var jsonString = '[' + jsonParts.join(',') + ']';
|
|
||||||
var items = JSON.parse(jsonString);
|
|
||||||
|
|
||||||
for (i = 0; i < items.length; i++) {
|
for (i = 0; i < fileLines.length; i++) {
|
||||||
var item = items[i];
|
var line = fileLines[i];
|
||||||
|
if (!line.length || line[0] !== '{') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var item = JSON.parse(line);
|
||||||
if (item.typeName !== 'webforms.WebForm') {
|
if (item.typeName !== 'webforms.WebForm') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -576,7 +604,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (item.secureContents) {
|
if (item.secureContents) {
|
||||||
if (item.secureContents.notesPlain) {
|
if (item.secureContents.notesPlain && item.secureContents.notesPlain !== '') {
|
||||||
site.notes = item.secureContents.notesPlain;
|
site.notes = item.secureContents.notesPlain;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -614,5 +642,345 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function importChromeCsv(file, success, error) {
|
||||||
|
Papa.parse(file, {
|
||||||
|
header: true,
|
||||||
|
encoding: 'UTF-8',
|
||||||
|
complete: function (results) {
|
||||||
|
parseCsvErrors(results);
|
||||||
|
|
||||||
|
var folders = [],
|
||||||
|
sites = [],
|
||||||
|
siteRelationships = [];
|
||||||
|
|
||||||
|
angular.forEach(results.data, function (value, key) {
|
||||||
|
sites.push({
|
||||||
|
favorite: false,
|
||||||
|
uri: value.url && value.url !== '' ? trimUri(value.url) : null,
|
||||||
|
username: value.username && value.username !== '' ? value.username : null,
|
||||||
|
password: value.password && value.password !== '' ? value.password : null,
|
||||||
|
notes: null,
|
||||||
|
name: value.name && value.name !== '' ? value.name : '--',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
success(folders, sites, siteRelationships);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function importFirefoxPasswordExporterCsvXml(file, success, error) {
|
||||||
|
var folders = [],
|
||||||
|
sites = [],
|
||||||
|
siteRelationships = [];
|
||||||
|
|
||||||
|
function getNameFromHost(host) {
|
||||||
|
var name = '--';
|
||||||
|
try {
|
||||||
|
if (host && host !== '') {
|
||||||
|
var parser = document.createElement('a');
|
||||||
|
parser.href = host;
|
||||||
|
if (parser.hostname) {
|
||||||
|
name = parser.hostname;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file.type === 'text/xml') {
|
||||||
|
var reader = new FileReader();
|
||||||
|
reader.readAsText(file, 'utf-8');
|
||||||
|
reader.onload = function (evt) {
|
||||||
|
var xmlDoc = $.parseXML(evt.target.result),
|
||||||
|
xml = $(xmlDoc);
|
||||||
|
|
||||||
|
var entries = xml.find('entry');
|
||||||
|
for (var i = 0; i < entries.length; i++) {
|
||||||
|
var entry = $(entries[i]);
|
||||||
|
if (!entry) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var host = entry.attr('host'),
|
||||||
|
user = entry.attr('user'),
|
||||||
|
password = entry.attr('password');
|
||||||
|
|
||||||
|
sites.push({
|
||||||
|
favorite: false,
|
||||||
|
uri: host && host !== '' ? trimUri(host) : null,
|
||||||
|
username: user && user !== '' ? user : null,
|
||||||
|
password: password && password !== '' ? password : null,
|
||||||
|
notes: null,
|
||||||
|
name: getNameFromHost(host),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
success(folders, sites, siteRelationships);
|
||||||
|
};
|
||||||
|
|
||||||
|
reader.onerror = function (evt) {
|
||||||
|
error();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// currently bugged due to the comment
|
||||||
|
// ref: https://github.com/mholt/PapaParse/issues/351
|
||||||
|
|
||||||
|
error('Only .xml exports are supported.');
|
||||||
|
return;
|
||||||
|
|
||||||
|
//Papa.parse(file, {
|
||||||
|
// comments: '#',
|
||||||
|
// header: true,
|
||||||
|
// encoding: 'UTF-8',
|
||||||
|
// complete: function (results) {
|
||||||
|
// parseCsvErrors(results);
|
||||||
|
|
||||||
|
// angular.forEach(results.data, function (value, key) {
|
||||||
|
// sites.push({
|
||||||
|
// favorite: false,
|
||||||
|
// uri: value.hostname && value.hostname !== '' ? trimUri(value.hostname) : null,
|
||||||
|
// username: value.username && value.username !== '' ? value.username : null,
|
||||||
|
// password: value.password && value.password !== '' ? value.password : null,
|
||||||
|
// notes: null,
|
||||||
|
// name: getNameFromHost(value.hostname),
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
|
||||||
|
// success(folders, sites, siteRelationships);
|
||||||
|
// }
|
||||||
|
//});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function importUpmCsv(file, success, error) {
|
||||||
|
Papa.parse(file, {
|
||||||
|
encoding: 'UTF-8',
|
||||||
|
complete: function (results) {
|
||||||
|
parseCsvErrors(results);
|
||||||
|
|
||||||
|
var folders = [],
|
||||||
|
sites = [],
|
||||||
|
siteRelationships = [];
|
||||||
|
|
||||||
|
angular.forEach(results.data, function (value, key) {
|
||||||
|
if (value.length === 5) {
|
||||||
|
sites.push({
|
||||||
|
favorite: false,
|
||||||
|
uri: value[3] && value[3] !== '' ? trimUri(value[3]) : null,
|
||||||
|
username: value[1] && value[1] !== '' ? value[1] : null,
|
||||||
|
password: value[2] && value[2] !== '' ? value[2] : null,
|
||||||
|
notes: value[4] && value[4] !== '' ? value[4] : null,
|
||||||
|
name: value[0] && value[0] !== '' ? value[0] : '--',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
success(folders, sites, siteRelationships);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function importKeeperCsv(file, success, error) {
|
||||||
|
Papa.parse(file, {
|
||||||
|
encoding: 'UTF-8',
|
||||||
|
complete: function (results) {
|
||||||
|
parseCsvErrors(results);
|
||||||
|
|
||||||
|
var folders = [],
|
||||||
|
sites = [],
|
||||||
|
folderRelationships = [];
|
||||||
|
|
||||||
|
angular.forEach(results.data, function (value, key) {
|
||||||
|
if (value.length >= 6) {
|
||||||
|
var folderIndex = folders.length,
|
||||||
|
siteIndex = sites.length,
|
||||||
|
hasFolder = value[0] && value[0] !== '',
|
||||||
|
addFolder = hasFolder,
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
if (hasFolder) {
|
||||||
|
for (i = 0; i < folders.length; i++) {
|
||||||
|
if (folders[i].name === value[0]) {
|
||||||
|
addFolder = false;
|
||||||
|
folderIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var site = {
|
||||||
|
favorite: false,
|
||||||
|
uri: value[4] && value[4] !== '' ? trimUri(value[4]) : null,
|
||||||
|
username: value[2] && value[2] !== '' ? value[2] : null,
|
||||||
|
password: value[3] && value[3] !== '' ? value[3] : null,
|
||||||
|
notes: value[5] && value[5] !== '' ? value[5] : null,
|
||||||
|
name: value[1] && value[1] !== '' ? value[1] : '--',
|
||||||
|
};
|
||||||
|
|
||||||
|
if (value.length > 6) {
|
||||||
|
// we have some custom fields. add them to notes.
|
||||||
|
|
||||||
|
if (site.notes === null) {
|
||||||
|
site.notes = '';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
site.notes += '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 6; i < value.length; i = i + 2) {
|
||||||
|
var cfName = value[i];
|
||||||
|
var cfValue = value[i + 1];
|
||||||
|
site.notes += (cfName + ': ' + cfValue + '\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sites.push(site);
|
||||||
|
|
||||||
|
if (addFolder) {
|
||||||
|
folders.push({
|
||||||
|
name: value[0]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasFolder) {
|
||||||
|
var relationship = {
|
||||||
|
key: siteIndex,
|
||||||
|
value: folderIndex
|
||||||
|
};
|
||||||
|
folderRelationships.push(relationship);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
success(folders, sites, folderRelationships);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function importPasswordDragonXml(file, success, error) {
|
||||||
|
var folders = [],
|
||||||
|
sites = [],
|
||||||
|
folderRelationships = [],
|
||||||
|
foldersIndex = [],
|
||||||
|
j = 0;
|
||||||
|
|
||||||
|
var reader = new FileReader();
|
||||||
|
reader.readAsText(file, 'utf-8');
|
||||||
|
reader.onload = function (evt) {
|
||||||
|
var xmlDoc = $.parseXML(evt.target.result),
|
||||||
|
xml = $(xmlDoc);
|
||||||
|
|
||||||
|
var pwManager = xml.find('PasswordManager');
|
||||||
|
if (pwManager.length) {
|
||||||
|
var records = pwManager.find('> record');
|
||||||
|
if (records.length) {
|
||||||
|
for (var i = 0; i < records.length; i++) {
|
||||||
|
var record = $(records[i]);
|
||||||
|
|
||||||
|
var accountNameNode = record.find('> Account-Name'),
|
||||||
|
accountName = accountNameNode.length ? $(accountNameNode) : null,
|
||||||
|
userIdNode = record.find('> User-Id'),
|
||||||
|
userId = userIdNode.length ? $(userIdNode) : null,
|
||||||
|
passwordNode = record.find('> Password'),
|
||||||
|
password = passwordNode.length ? $(passwordNode) : null,
|
||||||
|
urlNode = record.find('> URL'),
|
||||||
|
url = urlNode.length ? $(urlNode) : null,
|
||||||
|
notesNode = record.find('> Notes'),
|
||||||
|
notes = notesNode.length ? $(notesNode) : null,
|
||||||
|
categoryNode = record.find('> Category'),
|
||||||
|
category = categoryNode.length ? $(categoryNode) : null,
|
||||||
|
categoryText = category ? category.text() : null;
|
||||||
|
|
||||||
|
var folderIndex = folders.length,
|
||||||
|
siteIndex = sites.length,
|
||||||
|
hasFolder = categoryText && categoryText !== '' && categoryText !== 'Unfiled',
|
||||||
|
addFolder = hasFolder;
|
||||||
|
|
||||||
|
if (hasFolder) {
|
||||||
|
for (j = 0; j < folders.length; j++) {
|
||||||
|
if (folders[j].name === categoryText) {
|
||||||
|
addFolder = false;
|
||||||
|
folderIndex = j;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var site = {
|
||||||
|
favorite: false,
|
||||||
|
uri: url && url.text() !== '' ? trimUri(url.text()) : null,
|
||||||
|
username: userId && userId.text() !== '' ? userId.text() : null,
|
||||||
|
password: password && password.text() !== '' ? password.text() : null,
|
||||||
|
notes: notes && notes.text() !== '' ? notes.text() : null,
|
||||||
|
name: accountName && accountName.text() !== '' ? accountName.text() : '--',
|
||||||
|
};
|
||||||
|
|
||||||
|
var attributesSelector = '';
|
||||||
|
for (j = 1; j <= 10; j++) {
|
||||||
|
attributesSelector += '> Attribute-' + j;
|
||||||
|
if (j < 10) {
|
||||||
|
attributesSelector += ', ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var attributes = record.find(attributesSelector);
|
||||||
|
if (attributes.length) {
|
||||||
|
// we have some attributes. add them to notes.
|
||||||
|
for (j = 0; j < attributes.length; j++) {
|
||||||
|
var attr = $(attributes[j]),
|
||||||
|
attrName = attr.prop('tagName'),
|
||||||
|
attrValue = attr.text();
|
||||||
|
|
||||||
|
if (!attrValue || attrValue === '' || attrValue === 'null') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (site.notes === null) {
|
||||||
|
site.notes = '';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
site.notes += '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
site.notes += (attrName + ': ' + attrValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sites.push(site);
|
||||||
|
|
||||||
|
if (addFolder) {
|
||||||
|
folders.push({
|
||||||
|
name: categoryText
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasFolder) {
|
||||||
|
var relationship = {
|
||||||
|
key: siteIndex,
|
||||||
|
value: folderIndex
|
||||||
|
};
|
||||||
|
folderRelationships.push(relationship);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
success(folders, sites, folderRelationships);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
error();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
reader.onerror = function (evt) {
|
||||||
|
error();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return _service;
|
return _service;
|
||||||
});
|
});
|
||||||
2
src/app/settings.js
Normal file
2
src/app/settings.js
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
angular.module("bit")
|
||||||
|
.constant("appSettings", {"rememberedEmailCookieName":"bit.rememberedEmail","apiUri":"http://localhost:4000","version":"1.5.0","environment":"Development"});
|
||||||
@@ -19,17 +19,30 @@
|
|||||||
masterPasswordHash: _masterPasswordHash,
|
masterPasswordHash: _masterPasswordHash,
|
||||||
provider: 0 /* Only authenticator provider for now. */
|
provider: 0 /* Only authenticator provider for now. */
|
||||||
}, function (response) {
|
}, function (response) {
|
||||||
|
processResponse(response);
|
||||||
|
}).$promise;
|
||||||
|
};
|
||||||
|
|
||||||
|
function formatString(s) {
|
||||||
|
if (!s) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.replace(/(.{4})/g, '$1 ').trim().toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
function processResponse(response) {
|
||||||
var key = response.AuthenticatorKey;
|
var key = response.AuthenticatorKey;
|
||||||
$scope.twoFactorModel = {
|
$scope.twoFactorModel = {
|
||||||
enabled: response.TwoFactorEnabled,
|
enabled: response.TwoFactorEnabled,
|
||||||
key: key.replace(/(.{4})/g, '$1 ').trim(),
|
key: formatString(key),
|
||||||
|
recovery: formatString(response.TwoFactorRecoveryCode),
|
||||||
qr: 'https://chart.googleapis.com/chart?chs=120x120&chld=L|0&cht=qr&chl=otpauth://totp/' +
|
qr: 'https://chart.googleapis.com/chart?chs=120x120&chld=L|0&cht=qr&chl=otpauth://totp/' +
|
||||||
_issuer + ':' + encodeURIComponent(_profile.email) +
|
_issuer + ':' + encodeURIComponent(_profile.email) +
|
||||||
'%3Fsecret=' + encodeURIComponent(key) +
|
'%3Fsecret=' + encodeURIComponent(key) +
|
||||||
'%26issuer=' + _issuer
|
'%26issuer=' + _issuer
|
||||||
};
|
};
|
||||||
}).$promise;
|
}
|
||||||
};
|
|
||||||
|
|
||||||
$scope.update = function (model) {
|
$scope.update = function (model) {
|
||||||
var currentlyEnabled = $scope.twoFactorModel.enabled;
|
var currentlyEnabled = $scope.twoFactorModel.enabled;
|
||||||
@@ -39,7 +52,7 @@
|
|||||||
|
|
||||||
var request = {
|
var request = {
|
||||||
enabled: !currentlyEnabled,
|
enabled: !currentlyEnabled,
|
||||||
token: model ? model.token : null,
|
token: model.token.replace(' ', ''),
|
||||||
masterPasswordHash: _masterPasswordHash
|
masterPasswordHash: _masterPasswordHash
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -48,14 +61,16 @@
|
|||||||
$analytics.eventTrack('Enabled Two-step Login');
|
$analytics.eventTrack('Enabled Two-step Login');
|
||||||
toastr.success('Two-step login has been enabled.');
|
toastr.success('Two-step login has been enabled.');
|
||||||
if (_profile.extended) _profile.extended.twoFactorEnabled = true;
|
if (_profile.extended) _profile.extended.twoFactorEnabled = true;
|
||||||
|
processResponse(response);
|
||||||
|
$('#token').blur();
|
||||||
|
model.token = null;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$analytics.eventTrack('Disabled Two-step Login');
|
$analytics.eventTrack('Disabled Two-step Login');
|
||||||
toastr.success('Two-step login has been disabled.');
|
toastr.success('Two-step login has been disabled.');
|
||||||
if (_profile.extended) _profile.extended.twoFactorEnabled = false;
|
if (_profile.extended) _profile.extended.twoFactorEnabled = false;
|
||||||
}
|
|
||||||
|
|
||||||
$scope.close();
|
$scope.close();
|
||||||
|
}
|
||||||
}).$promise;
|
}).$promise;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
<form name="updateTwoStepForm" ng-submit="updateTwoStepForm.$valid && update(updateModel)" api-form="updatePromise" ng-if="twoFactorModel">
|
<form name="updateTwoStepForm" ng-submit="updateTwoStepForm.$valid && update(updateModel)" api-form="updatePromise" ng-if="twoFactorModel">
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div ng-show="enabled()">
|
<div ng-show="enabled()">
|
||||||
<p>Two-step login is enabled on your account. Below is the code required by your verification app.</p>
|
<p>Two-step login is <strong class="text-green">enabled</strong> on your account. Below is the code required by your verification app.</p>
|
||||||
<p>Need a two-step verification app? Download one of the following:</p>
|
<p>Need a two-step verification app? Download one of the following:</p>
|
||||||
</div>
|
</div>
|
||||||
<div ng-show="!enabled()">
|
<div ng-show="!enabled()">
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
<h4>1. Download a two-step verification app</h4>
|
<h4>1. Download a two-step verification app</h4>
|
||||||
</div>
|
</div>
|
||||||
<ul class="fa-ul">
|
<ul class="fa-ul">
|
||||||
<li><i class="fa-li fa fa-apple"></i> iOS devices: <a href="https://itunes.apple.com/en/app/authy/id494168017" target="_blank">Authy for iOS</a></li>
|
<li><i class="fa-li fa fa-apple"></i> iOS devices: <a href="https://itunes.apple.com/us/app/authy/id494168017?mt=8" target="_blank">Authy for iOS</a></li>
|
||||||
<li><i class="fa-li fa fa-android"></i> Android devices: <a href="https://play.google.com/store/apps/details?id=com.authy.authy" target="_blank">Authy for Android</a></li>
|
<li><i class="fa-li fa fa-android"></i> Android devices: <a href="https://play.google.com/store/apps/details?id=com.authy.authy" target="_blank">Authy for Android</a></li>
|
||||||
<li><i class="fa-li fa fa-windows"></i> Windows devices: <a href="https://www.microsoft.com/en-us/store/apps/authenticator/9wzdncrfj3rj" target="_blank">Microsoft Authenticator </a></li>
|
<li><i class="fa-li fa fa-windows"></i> Windows devices: <a href="https://www.microsoft.com/en-us/store/apps/authenticator/9wzdncrfj3rj" target="_blank">Microsoft Authenticator </a></li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -47,35 +47,48 @@
|
|||||||
<div class="col-md-4 text-center">
|
<div class="col-md-4 text-center">
|
||||||
<p><img ng-src="{{twoFactorModel.qr}}" alt="QR" class="img-thumbnail" /></p>
|
<p><img ng-src="{{twoFactorModel.qr}}" alt="QR" class="img-thumbnail" /></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-8">
|
<div class="col-md-8">
|
||||||
<p><strong>Can't scan the code?</strong> You can add the code to your application manually using the following details:</p>
|
<p><strong>Can't scan the code?</strong> You can add the code to your application manually using the following details:</p>
|
||||||
<ul class="list-unstyled">
|
<ul class="list-unstyled">
|
||||||
<li><strong>Key:</strong> <samp>{{twoFactorModel.key}}</samp></li>
|
<li><strong>Key:</strong> <code>{{twoFactorModel.key}}</code></li>
|
||||||
<li><strong>Account:</strong> {{account}}</li>
|
<li><strong>Account:</strong> {{account}}</li>
|
||||||
<li><strong>Time based:</strong> Yes</li>
|
<li><strong>Time based:</strong> Yes</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div ng-show="!enabled()">
|
<div ng-show="enabled()">
|
||||||
|
<hr />
|
||||||
|
<h4>Recovery Code</h4>
|
||||||
|
<p>
|
||||||
|
The recovery code allows you to access your account in the event that you lose your authenticator app.
|
||||||
|
bitwarden support won't be able to assist you if you lose access to your account. We recommend you write down or
|
||||||
|
print the recovery code below and keep it in a safe place.
|
||||||
|
</p>
|
||||||
|
<ul class="list-unstyled">
|
||||||
|
<li>
|
||||||
|
<strong>Recovery Code:</strong> <code>{{twoFactorModel.recovery}}</code>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
<div class="callout callout-danger validation-errors" ng-show="updateTwoStepForm.$errors">
|
<div class="callout callout-danger validation-errors" ng-show="updateTwoStepForm.$errors">
|
||||||
<h4>Errors have occured</h4>
|
<h4>Errors have occured</h4>
|
||||||
<ul>
|
<ul>
|
||||||
<li ng-repeat="e in updateTwoStepForm.$errors">{{e}}</li>
|
<li ng-repeat="e in updateTwoStepForm.$errors">{{e}}</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<h4 style="margin-top: 30px;">3. Enter the resulting verification code from the app</h4>
|
<hr ng-show="enabled()" />
|
||||||
<div class="form-group" show-errors ng-show="!twoFactorModel.enabled">
|
<h4 style="margin-top: 30px;"><span ng-show="!enabled()">3. </span>Enter the resulting verification code from the app</h4>
|
||||||
|
<div class="form-group" show-errors>
|
||||||
<label for="token" class="sr-only">Verification Code</label>
|
<label for="token" class="sr-only">Verification Code</label>
|
||||||
<input type="number" id="token" name="Token" placeholder="Verification Code" ng-model="updateModel.token" class="form-control" ng-required="!twoFactorModel.enabled" api-field />
|
<input type="text" id="token" name="Token" placeholder="Verification Code" ng-model="updateModel.token" class="form-control" required api-field />
|
||||||
</div>
|
|
||||||
<p>NOTE: After enabling two-step login, you will be required to enter the current code generated by your verification app each time you log in.</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
<p ng-show="!enabled()">NOTE: After enabling two-step login, you will be required to enter the current code generated by your verification app each time you log in.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="submit" class="btn btn-primary btn-flat" ng-disabled="updateTwoStepForm.$loading">
|
<button type="submit" class="btn btn-primary btn-flat" ng-disabled="updateTwoStepForm.$loading">
|
||||||
<i class="fa fa-refresh fa-spin loading-icon" ng-show="updateTwoStepForm.$loading"></i>
|
<i class="fa fa-refresh fa-spin loading-icon" ng-show="updateTwoStepForm.$loading"></i>
|
||||||
<span ng-show="twoFactorModel.enabled">Disable Two-step</span>
|
<span ng-show="enabled()">Disable Two-step</span>
|
||||||
<span ng-show="!twoFactorModel.enabled">Enable Two-step</span>
|
<span ng-show="!enabled()">Enable Two-step</span>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="btn btn-default btn-flat" ng-click="close()">Close</button>
|
<button type="button" class="btn btn-default btn-flat" ng-click="close()">Close</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
function importSuccess(folders, sites, folderRelationships) {
|
function importSuccess(folders, sites, folderRelationships) {
|
||||||
if (!folders.length && !sites.length) {
|
if (!folders.length && !sites.length) {
|
||||||
|
$uibModalInstance.dismiss('cancel');
|
||||||
toastr.error('Nothing was imported.');
|
toastr.error('Nothing was imported.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -30,17 +31,42 @@
|
|||||||
}, importError);
|
}, importError);
|
||||||
}
|
}
|
||||||
|
|
||||||
function importError(errorMessage) {
|
function importError(error) {
|
||||||
$analytics.eventTrack('Import Data Failed', { label: $scope.model.source });
|
$analytics.eventTrack('Import Data Failed', { label: $scope.model.source });
|
||||||
$uibModalInstance.dismiss('cancel');
|
$uibModalInstance.dismiss('cancel');
|
||||||
if (errorMessage) {
|
|
||||||
toastr.error(errorMessage);
|
if (error) {
|
||||||
|
var data = error.data;
|
||||||
|
if (data && data.ValidationErrors) {
|
||||||
|
var message = '';
|
||||||
|
for (var key in data.ValidationErrors) {
|
||||||
|
if (!data.ValidationErrors.hasOwnProperty(key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < data.ValidationErrors[key].length; i++) {
|
||||||
|
message += (key + ': ' + data.ValidationErrors[key][i] + ' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message !== '') {
|
||||||
|
toastr.error(message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (data && data.Message) {
|
||||||
|
toastr.error(data.Message);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
toastr.error('Something went wrong. Try again.', 'Oh No!');
|
toastr.error(error);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toastr.error('Something went wrong. Try again.', 'Oh No!');
|
||||||
|
}
|
||||||
|
|
||||||
$scope.close = function () {
|
$scope.close = function () {
|
||||||
$uibModalInstance.dismiss('cancel');
|
$uibModalInstance.dismiss('cancel');
|
||||||
};
|
};
|
||||||
@@ -9,11 +9,16 @@
|
|||||||
<select id="source" name="source" class="form-control" ng-model="model.source">
|
<select id="source" name="source" class="form-control" ng-model="model.source">
|
||||||
<option value="local">bitwarden (csv)</option>
|
<option value="local">bitwarden (csv)</option>
|
||||||
<option value="lastpass">LastPass (csv)</option>
|
<option value="lastpass">LastPass (csv)</option>
|
||||||
|
<option value="chromecsv">Chrome (csv)</option>
|
||||||
|
<option value="firefoxpasswordexportercsvxml">Firefox Password Exporter (xml)</option>
|
||||||
<option value="safeincloudxml">SafeInCloud (xml)</option>
|
<option value="safeincloudxml">SafeInCloud (xml)</option>
|
||||||
<option value="safeincloudcsv">SafeInCloud (csv)</option>
|
<option value="safeincloudcsv">SafeInCloud (csv)</option>
|
||||||
<option value="keypassxml">KeyPass (xml)</option>
|
<option value="keypassxml">KeyPass (xml)</option>
|
||||||
<option value="padlockcsv">Padlock (csv)</option>
|
<option value="padlockcsv">Padlock (csv)</option>
|
||||||
<option value="1password1pif">1Password (1pif)</option>
|
<option value="1password1pif">1Password (1pif)</option>
|
||||||
|
<option value="upmcsv">Universal Password Manager (csv)</option>
|
||||||
|
<option value="keepercsv">Keeper (csv)</option>
|
||||||
|
<option value="passworddragonxml">Password Dragon (xml)</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -37,6 +37,10 @@
|
|||||||
alert('Your web browser does not support easy clipboard copying. Copy it manually instead.');
|
alert('Your web browser does not support easy clipboard copying. Copy it manually instead.');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.folderSort = function (item) {
|
||||||
|
return item.name.toLowerCase();
|
||||||
|
};
|
||||||
|
|
||||||
function selectPassword(e) {
|
function selectPassword(e) {
|
||||||
var target = $(e.trigger).parent().prev();
|
var target = $(e.trigger).parent().prev();
|
||||||
if (target.attr('type') === 'text') {
|
if (target.attr('type') === 'text') {
|
||||||
@@ -77,13 +77,25 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
editModel.result.then(function (editedSite) {
|
editModel.result.then(function (returnVal) {
|
||||||
var site = $filter('filter')($scope.sites, { id: editedSite.id }, true);
|
if (returnVal.action === 'edit') {
|
||||||
if (site && site.length > 0) {
|
var siteToUpdate = $filter('filter')($scope.sites, { id: returnVal.data.id }, true);
|
||||||
site[0].folderId = editedSite.folderId;
|
|
||||||
site[0].name = editedSite.name;
|
if (siteToUpdate && siteToUpdate.length > 0) {
|
||||||
site[0].username = editedSite.username;
|
siteToUpdate[0].folderId = returnVal.data.folderId;
|
||||||
site[0].favorite = editedSite.favorite;
|
siteToUpdate[0].name = returnVal.data.name;
|
||||||
|
siteToUpdate[0].username = returnVal.data.username;
|
||||||
|
siteToUpdate[0].favorite = returnVal.data.favorite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (returnVal.action === 'delete') {
|
||||||
|
var siteToDelete = $filter('filter')($scope.sites, { id: returnVal.data }, true);
|
||||||
|
if (siteToDelete && siteToDelete.length > 0) {
|
||||||
|
var index = $scope.sites.indexOf(siteToDelete[0]);
|
||||||
|
if (index > -1) {
|
||||||
|
$scope.sites.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -115,7 +127,9 @@
|
|||||||
|
|
||||||
apiService.sites.del({ id: site.id }, function () {
|
apiService.sites.del({ id: site.id }, function () {
|
||||||
var index = $scope.sites.indexOf(site);
|
var index = $scope.sites.indexOf(site);
|
||||||
|
if (index > -1) {
|
||||||
$scope.sites.splice(index, 1);
|
$scope.sites.splice(index, 1);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -162,7 +176,9 @@
|
|||||||
|
|
||||||
apiService.folders.del({ id: folder.id }, function () {
|
apiService.folders.del({ id: folder.id }, function () {
|
||||||
var index = $scope.folders.indexOf(folder);
|
var index = $scope.folders.indexOf(folder);
|
||||||
|
if (index > -1) {
|
||||||
$scope.folders.splice(index, 1);
|
$scope.folders.splice(index, 1);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -15,7 +15,10 @@
|
|||||||
$scope.savePromise = apiService.sites.put({ id: siteId }, site, function (siteResponse) {
|
$scope.savePromise = apiService.sites.put({ id: siteId }, site, function (siteResponse) {
|
||||||
$analytics.eventTrack('Edited Site');
|
$analytics.eventTrack('Edited Site');
|
||||||
var decSite = cipherService.decryptSite(siteResponse);
|
var decSite = cipherService.decryptSite(siteResponse);
|
||||||
$uibModalInstance.close(decSite);
|
$uibModalInstance.close({
|
||||||
|
action: 'edit',
|
||||||
|
data: decSite
|
||||||
|
});
|
||||||
}).$promise;
|
}).$promise;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -38,6 +41,10 @@
|
|||||||
alert('Your web browser does not support easy clipboard copying. Copy it manually instead.');
|
alert('Your web browser does not support easy clipboard copying. Copy it manually instead.');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.folderSort = function (item) {
|
||||||
|
return item.name.toLowerCase();
|
||||||
|
};
|
||||||
|
|
||||||
function selectPassword(e) {
|
function selectPassword(e) {
|
||||||
var target = $(e.trigger).parent().prev();
|
var target = $(e.trigger).parent().prev();
|
||||||
if (target.attr('type') === 'text') {
|
if (target.attr('type') === 'text') {
|
||||||
@@ -45,6 +52,19 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$scope.delete = function () {
|
||||||
|
if (!confirm('Are you sure you want to delete this site (' + $scope.site.name + ')?')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
apiService.sites.del({ id: $scope.site.id }, function () {
|
||||||
|
$uibModalInstance.close({
|
||||||
|
action: 'delete',
|
||||||
|
data: $scope.site.id
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
$scope.close = function () {
|
$scope.close = function () {
|
||||||
$uibModalInstance.dismiss('cancel');
|
$uibModalInstance.dismiss('cancel');
|
||||||
};
|
};
|
||||||
@@ -12,6 +12,9 @@
|
|||||||
<div class="box-header with-border">
|
<div class="box-header with-border">
|
||||||
<h3 class="box-title"><i class="fa fa-folder-open"></i> {{folder.name}}</h3>
|
<h3 class="box-title"><i class="fa fa-folder-open"></i> {{folder.name}}</h3>
|
||||||
<div class="box-tools pull-right">
|
<div class="box-tools pull-right">
|
||||||
|
<button type="button" class="btn btn-box-tool" ng-click="addSite(folder)" uib-tooltip="Add Site">
|
||||||
|
<i class="fa fa-plus"></i>
|
||||||
|
</button>
|
||||||
<button type="button" class="btn btn-box-tool" ng-click="deleteFolder(folder)" ng-show="canDeleteFolder(folder)" uib-tooltip="Delete">
|
<button type="button" class="btn btn-box-tool" ng-click="deleteFolder(folder)" ng-show="canDeleteFolder(folder)" uib-tooltip="Delete">
|
||||||
<i class="fa fa-trash"></i>
|
<i class="fa fa-trash"></i>
|
||||||
</button>
|
</button>
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
<div class="form-group" show-errors>
|
<div class="form-group" show-errors>
|
||||||
<label for="folder">Folder</label>
|
<label for="folder">Folder</label>
|
||||||
<select id="folder" name="FolderId" ng-model="site.folderId" class="form-control" api-field>
|
<select id="folder" name="FolderId" ng-model="site.folderId" class="form-control" api-field>
|
||||||
<option ng-repeat="folder in folders" value="{{folder.id}}">{{folder.name}}</option>
|
<option ng-repeat="folder in folders | orderBy: folderSort" value="{{folder.id}}">{{folder.name}}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
<div class="form-group" show-errors>
|
<div class="form-group" show-errors>
|
||||||
<label for="folder">Folder</label>
|
<label for="folder">Folder</label>
|
||||||
<select id="folder" name="FolderId" ng-model="site.folderId" class="form-control" api-field>
|
<select id="folder" name="FolderId" ng-model="site.folderId" class="form-control" api-field>
|
||||||
<option ng-repeat="folder in folders" value="{{folder.id}}">{{folder.name}}</option>
|
<option ng-repeat="folder in folders | orderBy: folderSort" value="{{folder.id}}">{{folder.name}}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -97,5 +97,8 @@
|
|||||||
<i class="fa fa-refresh fa-spin loading-icon" ng-show="editSiteForm.$loading"></i>Save
|
<i class="fa fa-refresh fa-spin loading-icon" ng-show="editSiteForm.$loading"></i>Save
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="btn btn-default btn-flat" ng-click="close()">Close</button>
|
<button type="button" class="btn btn-default btn-flat" ng-click="close()">Close</button>
|
||||||
|
<button type="button" class="btn btn-link pull-right" ng-click="delete()" uib-tooltip="Delete">
|
||||||
|
<i class="fa fa-trash fa-lg"></i>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@@ -107,7 +107,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="https://bitwarden.com/contact/" target="_blank"
|
<a href="https://help.bitwarden.com/" target="_blank"
|
||||||
analytics-on="click" analytics-event="Clicked Get Help">
|
analytics-on="click" analytics-event="Clicked Get Help">
|
||||||
<i class="fa fa-info-circle"></i> <span>Get Help</span>
|
<i class="fa fa-info-circle"></i> <span>Get Help</span>
|
||||||
</a>
|
</a>
|
||||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
@@ -110,6 +110,7 @@
|
|||||||
<script src="app/accounts/accountsLogoutController.js"></script>
|
<script src="app/accounts/accountsLogoutController.js"></script>
|
||||||
<script src="app/accounts/accountsRegisterController.js"></script>
|
<script src="app/accounts/accountsRegisterController.js"></script>
|
||||||
<script src="app/accounts/accountsPasswordHintController.js"></script>
|
<script src="app/accounts/accountsPasswordHintController.js"></script>
|
||||||
|
<script src="app/accounts/accountsRecoverController.js"></script>
|
||||||
|
|
||||||
<script src="app/vault/vaultModule.js"></script>
|
<script src="app/vault/vaultModule.js"></script>
|
||||||
<script src="app/vault/vaultController.js"></script>
|
<script src="app/vault/vaultController.js"></script>
|
||||||
47
src/less/theme.less
Normal file
47
src/less/theme.less
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
@import url(https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700,300italic,400italic,600italic);
|
||||||
|
@import "../../node_modules/toastr/toastr.less";
|
||||||
|
|
||||||
|
/* Start AdminLTE */
|
||||||
|
|
||||||
|
//Bootstrap Variables & Mixins
|
||||||
|
//The core bootstrap code have not been modified. These files
|
||||||
|
//are included only for reference.
|
||||||
|
@import (reference) "../../node_modules/admin-lte/build/bootstrap-less/mixins.less";
|
||||||
|
@import (reference) "../../node_modules/admin-lte/build/bootstrap-less/variables.less";
|
||||||
|
//MISC
|
||||||
|
//----
|
||||||
|
@import "../../node_modules/admin-lte/build/less/core.less";
|
||||||
|
@import "../../node_modules/admin-lte/build/less/variables.less";
|
||||||
|
@import "../../node_modules/admin-lte/build/less/mixins.less";
|
||||||
|
//COMPONENTS
|
||||||
|
//-----------
|
||||||
|
@import "../../node_modules/admin-lte/build/less/header.less";
|
||||||
|
@import "../../node_modules/admin-lte/build/less/sidebar.less";
|
||||||
|
@import "../../node_modules/admin-lte/build/less/sidebar-mini.less";
|
||||||
|
@import "../../node_modules/admin-lte/build/less/control-sidebar.less";
|
||||||
|
@import "../../node_modules/admin-lte/build/less/dropdown.less";
|
||||||
|
@import "../../node_modules/admin-lte/build/less/forms.less";
|
||||||
|
@import "../../node_modules/admin-lte/build/less/progress-bars.less";
|
||||||
|
@import "../../node_modules/admin-lte/build/less/small-box.less";
|
||||||
|
@import "../../node_modules/admin-lte/build/less/boxes.less";
|
||||||
|
@import "../../node_modules/admin-lte/build/less/info-box.less";
|
||||||
|
@import "../../node_modules/admin-lte/build/less/timeline.less";
|
||||||
|
@import "../../node_modules/admin-lte/build/less/buttons.less";
|
||||||
|
@import "../../node_modules/admin-lte/build/less/callout.less";
|
||||||
|
@import "../../node_modules/admin-lte/build/less/alerts.less";
|
||||||
|
@import "../../node_modules/admin-lte/build/less/navs.less";
|
||||||
|
@import "../../node_modules/admin-lte/build/less/table.less";
|
||||||
|
@import "../../node_modules/admin-lte/build/less/labels.less";
|
||||||
|
@import "../../node_modules/admin-lte/build/less/modal.less";
|
||||||
|
//PAGES
|
||||||
|
//------
|
||||||
|
@import "../../node_modules/admin-lte/build/less/login_and_register.less";
|
||||||
|
@import "../../node_modules/admin-lte/build/less/404_500_errors.less";
|
||||||
|
//Miscellaneous
|
||||||
|
//-------------
|
||||||
|
@import "../../node_modules/admin-lte/build/less/miscellaneous.less";
|
||||||
|
@import "../../node_modules/admin-lte/build/less/print.less";
|
||||||
|
|
||||||
|
/* End AdminLTE */
|
||||||
|
|
||||||
|
@import "../../node_modules/admin-lte/build/less/skins/skin-blue.less";
|
||||||
Reference in New Issue
Block a user