1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-15 07:43:35 +00:00

Merge pull request #367 from bitwarden/typescript

Typescript conversion
This commit is contained in:
Kyle Spearrin
2017-11-09 22:45:30 -05:00
committed by GitHub
178 changed files with 7362 additions and 41201 deletions

5
src/background.d.ts vendored Normal file
View 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;

View File

@@ -1,33 +1,6 @@
<html>
<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>
<body>
</body>
</html>
</html>

View File

@@ -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,
bg_utilsService,
bg_i18nService,
@@ -28,27 +94,25 @@ var bg_isBackground = true,
bg_sidebarAction = (typeof opr !== 'undefined') && opr.sidebarAction ? opr.sidebarAction : chrome.sidebarAction;
// init services
bg_utilsService = new UtilsService();
bg_i18nService = new i18nService(bg_utilsService);
bg_constantsService = new ConstantsService(bg_i18nService);
bg_cryptoService = new CryptoService(bg_constantsService, bg_utilsService);
bg_tokenService = new TokenService(bg_utilsService);
bg_appIdService = new AppIdService(bg_utilsService);
bg_apiService = new ApiService(bg_tokenService, bg_appIdService, bg_utilsService, bg_constantsService, logout);
bg_environmentService = new EnvironmentService(bg_constantsService, bg_apiService);
bg_userService = new UserService(bg_tokenService, bg_apiService, bg_cryptoService, bg_utilsService);
bg_settingsService = new SettingsService(bg_userService, bg_utilsService);
bg_cipherService = new CipherService(bg_cryptoService, bg_userService, bg_apiService, bg_settingsService, bg_utilsService,
bg_constantsService);
bg_folderService = new FolderService(bg_cryptoService, bg_userService, bg_apiService, bg_i18nService, bg_utilsService);
bg_lockService = new LockService(bg_constantsService, bg_cryptoService, bg_folderService, bg_cipherService, bg_utilsService,
setIcon, refreshBadgeAndMenu);
bg_syncService = new SyncService(bg_cipherService, bg_folderService, bg_userService, bg_apiService, bg_settingsService,
bg_cryptoService, logout);
bg_passwordGenerationService = new PasswordGenerationService(bg_constantsService, bg_utilsService, bg_cryptoService);
bg_totpService = new TotpService(bg_constantsService);
bg_autofillService = new AutofillService(bg_utilsService, bg_totpService, bg_tokenService, bg_cipherService,
bg_constantsService);
window.bg_utilsService = bg_utilsService = new UtilsService();
window.bg_i18nService = bg_i18nService = new i18nService(bg_utilsService);
window.bg_constantsService = bg_constantsService = new ConstantsService(bg_i18nService);
window.bg_cryptoService = bg_cryptoService = new CryptoService();
window.bg_tokenService = bg_tokenService = new TokenService();
window.bg_appIdService = bg_appIdService = new AppIdService();
window.bg_apiService = bg_apiService = new ApiService(bg_tokenService, logout);
window.bg_environmentService = bg_environmentService = new EnvironmentService(bg_apiService);
window.bg_userService = bg_userService = new UserService(bg_tokenService);
window.bg_settingsService = bg_settingsService = new SettingsService(bg_userService);
window.bg_cipherService = bg_cipherService = new CipherService(bg_cryptoService, bg_userService, bg_settingsService, bg_apiService);
window.bg_folderService = bg_folderService = new FolderService(bg_cryptoService, bg_userService, bg_i18nService, bg_apiService);
window.bg_lockService = bg_lockService = new LockService(bg_cipherService, bg_folderService, bg_cryptoService, bg_utilsService, setIcon, refreshBadgeAndMenu);
window.bg_syncService = bg_syncService = new SyncService(bg_userService, bg_apiService, bg_settingsService, bg_folderService, bg_cipherService, bg_cryptoService, logout);
window.bg_passwordGenerationService = bg_passwordGenerationService = new PasswordGenerationService(bg_cryptoService);
window.bg_totpService = bg_totpService = new TotpService();
window.bg_autofillService = bg_autofillService = new AutofillService(bg_cipherService, bg_tokenService, bg_totpService, bg_utilsService);
require('./scripts/analytics.js');
if (chrome.commands) {
chrome.commands.onCommand.addListener(function (command) {
@@ -58,7 +122,7 @@ var bg_isBackground = true,
eventAction: 'Generated Password From Command'
});
bg_passwordGenerationService.getOptions().then(function (options) {
var password = bg_passwordGenerationService.generatePassword(options);
var password = PasswordGenerationService.generatePassword(options);
bg_utilsService.copyToClipboard(password);
bg_passwordGenerationService.addHistory(password);
});
@@ -193,7 +257,7 @@ var bg_isBackground = true,
eventAction: 'Generated Password From Context Menu'
});
bg_passwordGenerationService.getOptions().then(function (options) {
var password = bg_passwordGenerationService.generatePassword(options);
var password = PasswordGenerationService.generatePassword(options);
bg_utilsService.copyToClipboard(password);
bg_passwordGenerationService.addHistory(password);
});
@@ -384,19 +448,21 @@ var bg_isBackground = true,
return;
}
bg_userService.isAuthenticated(function (isAuthenticated) {
bg_cryptoService.getKey().then(function (key) {
var suffix = '';
if (!isAuthenticated) {
suffix = '_gray';
}
else if (!key) {
suffix = '_locked';
}
var isAuthenticated;
bg_userService.isAuthenticated().then(function (theIsAuthenticated) {
isAuthenticated = theIsAuthenticated;
return bg_cryptoService.getKey();
}).then(function (key) {
var suffix = '';
if (!isAuthenticated) {
suffix = '_gray';
}
else if (!key) {
suffix = '_locked';
}
actionSetIcon(chrome.browserAction, suffix);
actionSetIcon(bg_sidebarAction, suffix);
});
actionSetIcon(chrome.browserAction, suffix);
actionSetIcon(bg_sidebarAction, suffix);
});
function actionSetIcon(theAction, suffix) {
@@ -845,24 +911,25 @@ var bg_isBackground = true,
}
function logout(expired, callback) {
bg_syncService.setLastSync(new Date(0), function () {
bg_userService.getUserIdPromise().then(function (userId) {
return Q.all([
bg_tokenService.clearToken(),
bg_cryptoService.clearKeys(),
bg_userService.clear(),
bg_settingsService.clear(userId),
bg_cipherService.clear(userId),
bg_folderService.clear(userId),
bg_passwordGenerationService.clear()
]).then(function () {
chrome.runtime.sendMessage({
command: 'doneLoggingOut', expired: expired
});
setIcon();
refreshBadgeAndMenu();
callback();
bg_userService.getUserId().then(function (userId) {
return Promise.all([
bg_syncService.setLastSync(new Date(0)),
bg_tokenService.clearToken(),
bg_cryptoService.clearKeys(),
bg_userService.clear(),
bg_settingsService.clear(userId),
bg_cipherService.clear(userId),
bg_folderService.clear(userId),
bg_passwordGenerationService.clear()
]).then(function () {
chrome.runtime.sendMessage({
command: 'doneLoggingOut', expired: expired
});
setIcon();
refreshBadgeAndMenu();
if (callback) {
callback();
}
});
});
}
@@ -873,7 +940,7 @@ var bg_isBackground = true,
var syncInternal = 6 * 60 * 60 * 1000; // 6 hours
var lastSyncAgo = new Date() - lastSync;
if (override || !lastSync || lastSyncAgo >= syncInternal) {
bg_syncService.fullSync(override || false, function () {
bg_syncService.fullSync(override || false).then(function () {
scheduleNextSync();
});
}
@@ -893,7 +960,7 @@ var bg_isBackground = true,
// Bootstrap
bg_environmentService.setUrlsFromStorage(function () {
bg_environmentService.setUrlsFromStorage().then(function () {
setIcon();
cleanupbg_loginsToAdd();
fullSync(true);

32
src/content/autofill.css Normal file
View 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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,6 @@
export enum BrowserType {
Chrome = 2,
Firefox = 3,
Opera = 4,
Edge = 5,
}

View File

@@ -0,0 +1,6 @@
export enum CipherType {
Login = 1,
SecureNote = 2,
Card = 3,
Identity = 4,
}

View 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,
}

View File

@@ -0,0 +1,5 @@
export enum FieldType {
Text = 0,
Hidden = 1,
Boolean = 2,
}

View File

@@ -0,0 +1,3 @@
export enum SecureNoteType {
Generic = 0,
}

View File

@@ -50,6 +50,18 @@
"file:///*"
],
"run_at": "document_start"
},
{
"all_frames": true,
"css": [
"content/autofill.css"
],
"matches": [
"http://*/*",
"https://*/*",
"file:///*"
],
"run_at": "document_end"
}
],
"background": {
@@ -100,4 +112,4 @@
"overlay/popup.html",
"notification/bar.html"
]
}
}

View File

@@ -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;
};

View File

@@ -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);
}
};

View 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;

View 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;

View 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;

View 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;

View 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;

View 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;

View 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;

View 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;

View File

@@ -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;
};

View 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;

View 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;
}

View File

@@ -0,0 +1,7 @@
export default class AutofillForm {
opid: string;
htmlName: string;
htmlID: string;
htmlAction: string;
htmlMethod: string;
}

View 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;
}

View 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
View 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
View 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;

View 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;

View 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;
}
}

View File

@@ -0,0 +1,8 @@
import SymmetricCryptoKey from './symmetricCryptoKey';
export default class EncryptedObject {
iv: Uint8Array;
ct: Uint8Array;
mac: Uint8Array;
key: SymmetricCryptoKey;
}

View File

@@ -0,0 +1,5 @@
export default class EnvironmentUrls {
base: string;
api: string;
identity: string;
}

View 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;

View 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;

View 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;

View 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;

View File

@@ -0,0 +1,9 @@
export default class PasswordHistory {
password: string;
date: number;
constructor(password: string, date: number) {
this.password = password;
this.date = date;
}
}

View 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;

View 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;
}
}

View File

@@ -0,0 +1,9 @@
export default class SymmetricCryptoKeyBuffers {
key: ArrayBuffer;
encKey?: ArrayBuffer;
macKey?: ArrayBuffer;
constructor(key: ArrayBuffer) {
this.key = key;
}
}

View File

@@ -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;
});
}
})();

View 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;

View 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;

View File

@@ -0,0 +1,10 @@
class DeviceTokenRequest {
pushToken: string;
constructor() {
this.pushToken = null;
}
}
export { DeviceTokenRequest };
(window as any).DeviceTokenRequest = DeviceTokenRequest;

View 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;

View File

@@ -0,0 +1,10 @@
class PasswordHintRequest {
email: string;
constructor(email: string) {
this.email = email;
}
}
export { PasswordHintRequest };
(window as any).PasswordHintRequest = PasswordHintRequest;

View 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;

View 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;

View 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;

View 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;

View 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;

View 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;

View 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;

View 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;

View 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;

View 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;

View 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;

View 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;

View File

@@ -0,0 +1,10 @@
class ListResponse {
data: any;
constructor(data: any) {
this.data = data;
}
}
export { ListResponse };
(window as any).ListResponse = ListResponse;

View 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;

View 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;

View 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;

View File

@@ -3,7 +3,6 @@
<head>
<title></title>
<meta charset="utf-8" />
<link rel="stylesheet" type="text/css" href="bar.css" />
</head>
<body>
<table class="outter-table" cellpadding="0" cellspacing="0">
@@ -37,7 +36,5 @@
</table>
<div id="template-alert"></div>
</div>
<script src="../lib/jquery/jquery.js"></script>
<script src="bar.js"></script>
</body>
</html>

View File

@@ -1,63 +1,71 @@
$(function () {
var content = document.getElementById('content'),
closeButton = $('#close-button');
require('./bar.less');
// i18n
$('body').addClass('lang-' + chrome.i18n.getUILanguage());
document.addEventListener('DOMContentLoaded', function () {
// delay 50ms so that we get proper body dimensions
setTimeout(load, 50);
$('#logo-link').attr('title', chrome.i18n.getMessage('appName'));
closeButton.attr('title', chrome.i18n.getMessage('close'));
function load() {
var content = document.getElementById('content'),
closeButton = document.getElementById('close-button'),
body = document.querySelector('body'),
bodyRect = body.getBoundingClientRect();
if (window.innerWidth < 768) {
$('#template-add .add-save').text(chrome.i18n.getMessage('yes'));
$('#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'));
}
// i18n
body.classList.add('lang-' + chrome.i18n.getUILanguage());
$('#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')) {
setContent(document.getElementById('template-add'));
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
if (bodyRect.width < 768) {
document.querySelector('#template-add .add-save').textContent = chrome.i18n.getMessage('yes');
document.querySelector('#template-add .never-save').textContent = chrome.i18n.getMessage('never');
}
});
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) {
var query = window.location.search.substring(1);

View File

@@ -1,14 +1,16 @@
angular
angular
.module('bit.accounts')
.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.model = {};
utilsService.initListSectionItemListeners($(document), angular);
$('#email').focus();
$scope.submitPromise = null;
$scope.submit = function (model) {
if (!model.email) {
@@ -31,13 +33,11 @@
function hintPromise(request) {
return $q(function (resolve, reject) {
apiService.postPasswordHint(request,
function () {
resolve();
},
function (error) {
reject(error);
});
apiService.postPasswordHint(request).then(function () {
resolve();
}, function (error) {
reject(error);
});
});
}
});

View File

@@ -1,18 +1,19 @@
angular
angular
.module('bit.accounts')
.controller('accountsLoginController', function ($scope, $state, $stateParams, authService, userService, toastr,
utilsService, $analytics, i18nService) {
utilsService.initListSectionItemListeners($(document), angular);
utilsService, $analytics, i18nService, $timeout) {
$timeout(function () {
utilsService.initListSectionItemListeners(document, angular);
if ($stateParams.email) {
document.getElementById('master-password').focus();
}
else {
document.getElementById('email').focus();
}
}, 500);
$scope.i18n = i18nService;
if ($stateParams.email) {
$('#master-password').focus();
}
else {
$('#email').focus();
}
$scope.model = {
email: $stateParams.email
};

View File

@@ -1,11 +1,14 @@
angular
angular
.module('bit.accounts')
.controller('accountsLoginTwoFactorController', function ($scope, $state, authService, toastr, utilsService, SweetAlert,
$analytics, i18nService, $stateParams, $filter, constantsService, $timeout, $window, cryptoService, apiService,
environmentService) {
$timeout(function () {
utilsService.initListSectionItemListeners(document, angular);
}, 500);
$scope.i18n = i18nService;
utilsService.initListSectionItemListeners($(document), angular);
var customWebVaultUrl = null;
if (environmentService.baseUrl) {
@@ -85,7 +88,7 @@
}
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);
apiService.postTwoFactorEmail(request, function () {
if (doToast) {
@@ -143,7 +146,10 @@
u2f.cleanup();
$timeout(function () {
$('#code').focus();
var codeInput = document.getElementById('code');
if (codeInput) {
codeInput.focus();
}
var params;
if ($scope.providerType === constants.twoFactorProvider.duo) {
@@ -153,8 +159,10 @@
host: params.Host,
sig_request: params.Signature,
submit_callback: function (theForm) {
var response = $(theForm).find('input[name="sig_response"]').val();
$scope.login(response);
var sigElement = theForm.querySelector('input[name="sig_response"]');
if (sigElement) {
$scope.login(sigElement.value);
}
}
});
}

View File

@@ -1,15 +1,16 @@
angular
angular
.module('bit.accounts')
.controller(
'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.model = {};
utilsService.initListSectionItemListeners($(document), angular);
$('#email').focus();
$scope.submitPromise = null;
$scope.submit = function (model) {
if (!model.email) {
@@ -45,16 +46,16 @@
function registerPromise(key, masterPassword, email, hint) {
var deferred = $q.defer();
cryptoService.makeEncKey(key).then(function (encKey) {
cryptoService.hashPassword(masterPassword, key, function (hashedPassword) {
var request = new RegisterRequest(email, hashedPassword, hint, encKey.encryptedString);
apiService.postRegister(request,
function () {
deferred.resolve();
},
function (error) {
deferred.reject(error);
});
var encKey;
cryptoService.makeEncKey(key).then(function (theEncKey) {
encKey = theEncKey;
return cryptoService.hashPassword(masterPassword, key);
}).then(function (hashedPassword) {
var request = new RegisterRequest(email, hashedPassword, hint, encKey.encryptedString);
apiService.postRegister(request).then(function () {
deferred.resolve();
}, function (error) {
deferred.reject(error);
});
});
return deferred.promise;

View File

@@ -86,7 +86,7 @@
<div class="content">
<div class="two-factor-key-page">
<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 class="list">
<div class="list-section">
@@ -125,7 +125,7 @@
<p ng-if="!u2fReady">Loading...</p>
<div ng-if="u2fReady">
<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 class="list">

1
src/popup/app/app.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
declare module '*.html';

View File

@@ -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', [
'ui.router',
uiRouter,
'ngAnimate',
'toastr',
'angulartics',
'angulartics.google.analytics',
'bit.directives',
'bit.components',
'bit.services',
ComponentsModule,
ServicesModule,
'bit.global',
'bit.accounts',
'bit.current',
'bit.vault',
'bit.settings',
'bit.tools',
'bit.lock'
ToolsModule,
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']);
});

View 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,
};

View File

@@ -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);
};
};
}
});

View 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,
};

View File

@@ -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);
};
};
}
});

View 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;

View File

@@ -1,2 +0,0 @@
angular
.module('bit.components', []);

View File

@@ -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="" />
<i class="fa fa-fw fa-lg {{$ctrl.icon}}" ng-if="!$ctrl.imageEnabled || !$ctrl.image"></i>
</div>

View 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,
};

View File

@@ -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;
}
}
}
});

View File

@@ -1,4 +1,4 @@
angular
angular
.module('bit')
.config(function ($stateProvider, $urlRouterProvider, $compileProvider, $sceDelegateProvider, toastrConfig) {
@@ -23,20 +23,22 @@
var userService = $injector.get('userService');
var cryptoService = $injector.get('cryptoService');
cryptoService.getKey().then(function (key) {
userService.isAuthenticated(function (isAuthenticated) {
if (isAuthenticated) {
if (!key) {
$state.go('lock');
}
else {
$state.go('tabs.current');
}
var key;
cryptoService.getKey().then(function (theKey) {
key = theKey;
return userService.isAuthenticated();
}).then(function (isAuthenticated) {
if (isAuthenticated) {
if (!key) {
$state.go('lock');
}
else {
$state.go('home');
$state.go('tabs.current');
}
});
}
else {
$state.go('home');
}
});
});
@@ -44,21 +46,21 @@
.state('splash', {
url: '/splash',
controller: 'baseController',
templateUrl: 'app/global/splash.html',
template: require('./global/splash.html'),
data: { authorize: false },
params: { animation: null }
})
.state('privateMode', {
url: '/private-mode',
controller: 'privateModeController',
templateUrl: 'app/global/privateMode.html',
template: require('./global/privateMode.html'),
data: { authorize: false },
params: { animation: null }
})
.state('home', {
url: '/home',
controller: 'baseController',
templateUrl: 'app/global/home.html',
template: require('./global/home.html'),
data: { authorize: false },
params: { animation: null }
})
@@ -66,35 +68,35 @@
.state('login', {
url: '/login',
controller: 'accountsLoginController',
templateUrl: 'app/accounts/views/accountsLogin.html',
template: require('./accounts/views/accountsLogin.html'),
data: { authorize: false },
params: { animation: null, email: null }
})
.state('hint', {
url: '/hint',
controller: 'accountsHintController',
templateUrl: 'app/accounts/views/accountsHint.html',
template: require('./accounts/views/accountsHint.html'),
data: { authorize: false },
params: { animation: null }
})
.state('twoFactor', {
url: '/two-factor',
controller: 'accountsLoginTwoFactorController',
templateUrl: 'app/accounts/views/accountsLoginTwoFactor.html',
template: require('./accounts/views/accountsLoginTwoFactor.html'),
data: { authorize: false },
params: { animation: null, email: null, masterPassword: null, providers: null, provider: null }
})
.state('twoFactorMethods', {
url: '/two-factor-methods',
controller: 'accountsTwoFactorMethodsController',
templateUrl: 'app/accounts/views/accountsTwoFactorMethods.html',
template: require('./accounts/views/accountsTwoFactorMethods.html'),
data: { authorize: false },
params: { animation: null, email: null, masterPassword: null, providers: null, provider: null }
})
.state('register', {
url: '/register',
controller: 'accountsRegisterController',
templateUrl: 'app/accounts/views/accountsRegister.html',
template: require('./accounts/views/accountsRegister.html'),
data: { authorize: false },
params: { animation: null }
})
@@ -102,63 +104,62 @@
.state('tabs', {
url: '/tab',
abstract: true,
templateUrl: 'app/global/tabs.html',
template: require('./global/tabs.html'),
data: { authorize: true },
params: { animation: null }
})
.state('tabs.current', {
url: '/current',
templateUrl: 'app/current/views/current.html',
template: require('./current/views/current.html'),
controller: 'currentController'
})
.state('tabs.vault', {
url: '/vault',
templateUrl: 'app/vault/views/vault.html',
template: require('./vault/views/vault.html'),
controller: 'vaultController',
params: { syncOnLoad: false, searchText: null }
})
.state('tabs.settings', {
url: '/settings',
templateUrl: 'app/settings/views/settings.html',
template: require('./settings/views/settings.html'),
controller: 'settingsController'
})
.state('tabs.tools', {
url: '/tools',
templateUrl: 'app/tools/views/tools.html',
controller: 'toolsController'
component: 'tools'
})
.state('viewFolder', {
url: '/view-folder?folderId',
templateUrl: 'app/vault/views/vaultViewFolder.html',
template: require('./vault/views/vaultViewFolder.html'),
controller: 'vaultViewFolderController',
data: { authorize: true },
params: { animation: null, from: 'vault' }
})
.state('viewCipher', {
url: '/view-cipher?cipherId',
templateUrl: 'app/vault/views/vaultViewCipher.html',
template: require('./vault/views/vaultViewCipher.html'),
controller: 'vaultViewCipherController',
data: { authorize: true },
params: { animation: null, from: 'vault' }
})
.state('addCipher', {
url: '/add-cipher',
templateUrl: 'app/vault/views/vaultAddCipher.html',
template: require('./vault/views/vaultAddCipher.html'),
controller: 'vaultAddCipherController',
data: { authorize: true },
params: { animation: null, name: null, uri: null, folderId: null, cipher: null, from: 'vault' }
})
.state('editCipher', {
url: '/edit-cipher?cipherId',
templateUrl: 'app/vault/views/vaultEditCipher.html',
template: require('./vault/views/vaultEditCipher.html'),
controller: 'vaultEditCipherController',
data: { authorize: true },
params: { animation: null, fromView: true, cipher: null, from: 'vault' }
})
.state('attachments', {
url: '/attachments?id',
templateUrl: 'app/vault/views/vaultAttachments.html',
template: require('./vault/views/vaultAttachments.html'),
controller: 'vaultAttachmentsController',
data: { authorize: true },
params: { animation: null, fromView: true, from: 'vault' }
@@ -166,21 +167,20 @@
.state('passwordGenerator', {
url: '/password-generator',
templateUrl: 'app/tools/views/toolsPasswordGenerator.html',
controller: 'toolsPasswordGeneratorController',
component: 'passwordGenerator',
data: { authorize: true },
params: { animation: null, addState: null, editState: null }
})
.state('passwordGeneratorHistory', {
url: '/history',
templateUrl: 'app/tools/views/toolsPasswordGeneratorHistory.html',
template: require('./tools/views/toolsPasswordGeneratorHistory.html'),
controller: 'toolsPasswordGeneratorHistoryController',
data: { authorize: true },
params: { animation: null, addState: null, editState: null }
})
.state('export', {
url: '/export',
templateUrl: 'app/tools/views/toolsExport.html',
template: require('./tools/views/toolsExport.html'),
controller: 'toolsExportController',
data: { authorize: true },
params: { animation: null }
@@ -188,42 +188,42 @@
.state('about', {
url: '/about',
templateUrl: 'app/settings/views/settingsAbout.html',
template: require('./settings/views/settingsAbout.html'),
controller: 'settingsAboutController',
data: { authorize: true },
params: { animation: null }
})
.state('credits', {
url: '/credits',
templateUrl: 'app/settings/views/settingsCredits.html',
template: require('./settings/views/settingsCredits.html'),
controller: 'settingsCreditsController',
data: { authorize: true },
params: { animation: null }
})
.state('features', {
url: '/features',
templateUrl: 'app/settings/views/settingsFeatures.html',
template: require('./settings/views/settingsFeatures.html'),
controller: 'settingsFeaturesController',
data: { authorize: true },
params: { animation: null }
})
.state('help', {
url: '/help',
templateUrl: 'app/settings/views/settingsHelp.html',
template: require('./settings/views/settingsHelp.html'),
controller: 'settingsHelpController',
data: { authorize: true },
params: { animation: null }
})
.state('sync', {
url: '/sync',
templateUrl: 'app/settings/views/settingsSync.html',
template: require('./settings/views/settingsSync.html'),
controller: 'settingsSyncController',
data: { authorize: true },
params: { animation: null }
})
.state('premium', {
url: '/premium',
templateUrl: 'app/settings/views/settingsPremium.html',
template: require('./settings/views/settingsPremium.html'),
controller: 'settingsPremiumController',
data: { authorize: true },
params: { animation: null }
@@ -231,54 +231,60 @@
.state('folders', {
url: '/folders',
templateUrl: 'app/settings/views/settingsFolders.html',
template: require('./settings/views/settingsFolders.html'),
controller: 'settingsFoldersController',
data: { authorize: true },
params: { animation: null }
})
.state('addFolder', {
url: '/addFolder',
templateUrl: 'app/settings/views/settingsAddFolder.html',
template: require('./settings/views/settingsAddFolder.html'),
controller: 'settingsAddFolderController',
data: { authorize: true },
params: { animation: null }
})
.state('editFolder', {
url: '/editFolder?folderId',
templateUrl: 'app/settings/views/settingsEditFolder.html',
template: require('./settings/views/settingsEditFolder.html'),
controller: 'settingsEditFolderController',
data: { authorize: true },
params: { animation: null }
})
.state('environment', {
url: '/environment',
templateUrl: 'app/settings/views/settingsEnvironment.html',
template: require('./settings/views/settingsEnvironment.html'),
controller: 'settingsEnvironmentController',
data: { authorize: false },
params: { animation: null }
})
.state('lock', {
url: '/lock',
templateUrl: 'app/lock/views/lock.html',
controller: 'lockController',
component: 'lock',
data: { authorize: true },
params: { animation: null }
});
})
.run(function ($rootScope, userService, $state, constantsService, stateService) {
.run(function ($trace, $transitions, userService, $state, constantsService, stateService) {
//$trace.enable('TRANSITION');
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) {
stateService.removeState('vault');
stateService.removeState('viewFolder');
}
const userService = trans.injector().get('userService');
if (!userService) {
return;
}
userService.isAuthenticated(function (isAuthenticated) {
userService.isAuthenticated().then((isAuthenticated) => {
if (isAuthenticated) {
var obj = {};
obj[constantsService.lastActiveKey] = (new Date()).getTime();

View File

@@ -14,7 +14,7 @@ angular
$scope.otherCiphers = [];
$scope.loaded = false;
$scope.searchText = null;
$('#search').focus();
document.getElementById('search').focus();
$scope.$on('$viewContentLoaded', function () {
$timeout(loadVault, 100);

View File

@@ -1,11 +1,10 @@
angular
angular
.module('bit.directives')
.directive('fallbackSrc', function () {
return function (scope, element, attrs) {
var el = $(element);
el.bind('error', function (event) {
el.attr('src', attrs.fallbackSrc);
element[0].addEventListener('error', function (e) {
e.target.src = attrs.fallbackSrc;
});
};
});

View File

@@ -1,11 +1,11 @@
angular
angular
.module('bit.directives')
// ref: https://stackoverflow.com/a/14165848/1090359
.directive('stopClick', function () {
return function (scope, element, attrs) {
$(element).click(function (event) {
event.preventDefault();
element[0].addEventListener('click', function (e) {
e.preventDefault();
});
};
});

View File

@@ -1,10 +1,10 @@
angular
angular
.module('bit.directives')
.directive('stopProp', function () {
return function (scope, element, attrs) {
$(element).click(function (event) {
event.stopPropagation();
element[0].addEventListener('click', function (e) {
e.stopPropagation();
});
};
});
});

View File

@@ -2,7 +2,7 @@
<a ui-sref="environment({animation: 'in-slide-up'})" class="settings-icon">
<i class="fa fa-cog fa-lg"></i><span>&nbsp;Settings</span>
</a>
<img src="../../../../images/logo@2x.png" alt="bitwarden" />
<img src="../../../images/logo@2x.png" alt="bitwarden" />
<p>{{i18n.loginOrCreateNewAccount}}</p>
<div class="bottom-buttons">
<a class="btn btn-lg btn-primary btn-block" ui-sref="register({animation: 'in-slide-up'})"

View File

@@ -1,7 +1,7 @@
angular
.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) {
var self = this;
self.currentYear = new Date().getFullYear();
@@ -11,12 +11,13 @@ angular
self.disableSearch = utilsService && utilsService.isEdge();
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) {
self.animation = toParams.animation;
return;
}
else {
} else {
self.animation = '';
}
});
@@ -42,11 +43,12 @@ angular
href = hrefParts[0] + '?uilocation=popout' + (hrefParts.length > 0 ? '#' + hrefParts[1] : '');
}
var bodyRect = document.querySelector('body').getBoundingClientRect();
chrome.windows.create({
url: href,
type: 'popup',
width: $('body').width() + 60,
height: $('body').height()
width: bodyRect.width + 60,
height: bodyRect.height
});
if (utilsService.inPopup($window)) {

View File

@@ -1,5 +1,5 @@
<div class="content">
<div class="splash-page">
<img src="../../../../images/logo@3x.png" alt="bitwarden" />
<img src="../../../images/logo@3x.png" alt="bitwarden" />
</div>
</div>

View File

@@ -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="right">
<button type="submit" class="btn btn-link">{{i18n.submit}}</button>
<button type="submit" class="btn btn-link">{{$ctrl.i18n.submit}}</button>
</div>
<div class="title">{{i18n.verifyMasterPassword}}</div>
<div class="title">{{$ctrl.i18n.verifyMasterPassword}}</div>
</div>
<div class="content">
<div class="list">
@@ -11,15 +11,15 @@
<div class="list-section-items">
<div class="list-section-item list-section-item-icon-input">
<i class="fa fa-lock fa-lg fa-fw"></i>
<label for="master-password" class="sr-only">{{i18n.masterPass}}</label>
<input id="master-password" type="password" name="MasterPassword" placeholder="{{i18n.masterPass}}"
<label for="master-password" class="sr-only">{{$ctrl.i18n.masterPass}}</label>
<input id="master-password" type="password" name="MasterPassword" placeholder="{{$ctrl.i18n.masterPass}}"
ng-model="masterPassword">
</div>
</div>
</div>
</div>
<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>
</div>
</form>

View 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,
};

View 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;

View File

@@ -1,44 +0,0 @@
angular
.module('bit.lock')
.controller('lockController', function ($scope, $state, $analytics, i18nService, cryptoService, toastr,
userService, SweetAlert, $timeout) {
$scope.i18n = i18nService;
$timeout(function () {
$('#master-password').focus();
});
$scope.logOut = function () {
SweetAlert.swal({
title: i18nService.logOut,
text: i18nService.logOutConfirmation,
showCancelButton: true,
confirmButtonText: i18nService.yes,
cancelButtonText: i18nService.cancel
}, function (confirmed) {
if (confirmed) {
chrome.runtime.sendMessage({ command: 'logout' });
}
});
};
$scope.submit = function () {
userService.getEmail(function (email) {
var key = cryptoService.makeKey($scope.masterPassword, email);
cryptoService.hashPassword($scope.masterPassword, key, function (keyHash) {
cryptoService.getKeyHash(function (storedKeyHash) {
if (storedKeyHash && keyHash && storedKeyHash === keyHash) {
cryptoService.setKey(key).then(function () {
chrome.runtime.sendMessage({ command: 'unlocked' });
$state.go('tabs.current');
});
}
else {
toastr.error(i18nService.invalidMasterPassword, i18nService.errorsOccurred);
}
});
});
});
};
});

View File

@@ -1,2 +0,0 @@
angular
.module('bit.lock', ['ngAnimate', 'toastr']);

View File

@@ -0,0 +1,73 @@
import { DeviceRequest } from '../../../models/request/deviceRequest';
import { TokenRequest } from '../../../models/request/tokenRequest';
class AuthService {
constructor(public cryptoService: any, public apiService: any, public userService: any, public tokenService: any,
public $rootScope: any, public appIdService: any, public utilsService: any,
public constantsService: any) {
}
async logIn(email: string, masterPassword: string, twoFactorProvider?: number,
twoFactorToken?: string, remember?: boolean) {
email = email.toLowerCase();
const key = this.cryptoService.makeKey(masterPassword, email);
const appId = await this.appIdService.getAppId();
const storedTwoFactorToken = await this.tokenService.getTwoFactorToken(email);
const hashedPassword = await this.cryptoService.hashPassword(masterPassword, key);
const deviceRequest = new DeviceRequest(appId, this.utilsService);
let request: TokenRequest;
if (twoFactorToken != null && twoFactorProvider != null) {
request = new TokenRequest(email, hashedPassword, twoFactorProvider, twoFactorToken, remember,
deviceRequest);
} else if (storedTwoFactorToken) {
request = new TokenRequest(email, hashedPassword, this.constantsService.twoFactorProvider.remember,
storedTwoFactorToken, false, deviceRequest);
} else {
request = new TokenRequest(email, hashedPassword, null, null, false, deviceRequest);
}
const response = await this.apiService.postIdentityToken(request);
if (!response) {
return;
}
if (!response.accessToken) {
// two factor required
return {
twoFactor: true,
twoFactorProviders: response,
};
}
if (response.twoFactorToken) {
this.tokenService.setTwoFactorToken(response.twoFactorToken, email);
}
await this.tokenService.setTokens(response.accessToken, response.refreshToken);
await this.cryptoService.setKey(key);
await this.cryptoService.setKeyHash(hashedPassword);
await this.userService.setUserIdAndEmail(this.tokenService.getUserId(), this.tokenService.getEmail());
await this.cryptoService.setEncKey(response.key);
await this.cryptoService.setEncPrivateKey(response.privateKey);
chrome.runtime.sendMessage({ command: 'loggedIn' });
return {
twoFactor: false,
twoFactorProviders: null,
};
}
logOut(callback: Function) {
this.$rootScope.vaultCiphers = null;
this.$rootScope.vaultFolders = null;
callback();
}
}
export default AuthService;

View File

@@ -1,83 +0,0 @@
angular
.module('bit.services')
.factory('authService', function (cryptoService, apiService, userService, tokenService, $q, $rootScope,
folderService, settingsService, syncService, appIdService, utilsService, constantsService) {
var _service = {};
_service.logIn = function (email, masterPassword, twoFactorProvider, twoFactorToken, remember) {
email = email.toLowerCase();
var key = cryptoService.makeKey(masterPassword, email),
deferred = $q.defer(),
deviceRequest = null;
appIdService.getAppId().then(function (appId) {
deviceRequest = new DeviceRequest(appId, utilsService);
return tokenService.getTwoFactorToken(email);
}).then(function (twoFactorRememberedToken) {
cryptoService.hashPassword(masterPassword, key, function (hashedPassword) {
var request;
if (twoFactorToken && typeof (twoFactorProvider) !== 'undefined' && twoFactorProvider !== null) {
request = new TokenRequest(email, hashedPassword, twoFactorProvider, twoFactorToken, remember,
deviceRequest);
}
else if (twoFactorRememberedToken) {
request = new TokenRequest(email, hashedPassword, constantsService.twoFactorProvider.remember,
twoFactorRememberedToken, false, deviceRequest);
}
else {
request = new TokenRequest(email, hashedPassword, null, null, false, deviceRequest);
}
apiService.postIdentityToken(request, function (response) {
// success
if (!response || !response.accessToken) {
return;
}
if (response.twoFactorToken) {
tokenService.setTwoFactorToken(response.twoFactorToken, email, function () { });
}
tokenService.setTokens(response.accessToken, response.refreshToken, function () {
cryptoService.setKey(key).then(function () {
cryptoService.setKeyHash(hashedPassword, function () {
userService.setUserIdAndEmail(tokenService.getUserId(), tokenService.getEmail(),
function () {
cryptoService.setEncKey(response.key).then(function () {
return cryptoService.setEncPrivateKey(response.privateKey);
}).then(function () {
chrome.runtime.sendMessage({ command: 'loggedIn' });
deferred.resolve({
twoFactor: false,
twoFactorProviders: null
});
});
});
});
});
});
}, function (providers) {
// two factor required
deferred.resolve({
twoFactor: true,
twoFactorProviders: providers
});
}, function (error) {
// error
deferred.reject(error);
});
});
});
return deferred.promise;
};
_service.logOut = function (callback) {
$rootScope.vaultCiphers = null;
$rootScope.vaultFolders = null;
callback();
};
return _service;
});

View File

@@ -0,0 +1,24 @@
function getBackgroundService(service: string) {
return () => {
const page = chrome.extension.getBackgroundPage();
return page ? page['bg_' + service] : null;
};
}
export const tokenService = getBackgroundService('tokenService');
export const cryptoService = getBackgroundService('cryptoService');
export const userService = getBackgroundService('userService');
export const apiService = getBackgroundService('apiService');
export const folderService = getBackgroundService('folderService');
export const cipherService = getBackgroundService('cipherService');
export const syncService = getBackgroundService('syncService');
export const autofillService = getBackgroundService('autofillService');
export const passwordGenerationService = getBackgroundService('passwordGenerationService');
export const utilsService = getBackgroundService('utilsService');
export const appIdService = getBackgroundService('appIdService');
export const i18nService = getBackgroundService('i18nService');
export const constantsService = getBackgroundService('constantsService');
export const settingsService = getBackgroundService('settingsService');
export const lockService = getBackgroundService('lockService');
export const totpService = getBackgroundService('totpService');
export const environmentService = getBackgroundService('environmentService');

Some files were not shown because too many files have changed in this diff Show More