mirror of
https://github.com/bitwarden/web
synced 2025-12-29 06:33:28 +00:00
reorganize project folder structure and remove asp.net dependency
This commit is contained in:
54
src/app/services/apiService.js
Normal file
54
src/app/services/apiService.js
Normal file
@@ -0,0 +1,54 @@
|
||||
angular
|
||||
.module('bit.services')
|
||||
|
||||
.factory('apiService', function ($resource, tokenService, appSettings) {
|
||||
var _service = {},
|
||||
_apiUri = appSettings.apiUri;
|
||||
|
||||
_service.sites = $resource(_apiUri + '/sites/:id', {}, {
|
||||
get: { method: 'GET', params: { id: '@id' } },
|
||||
list: { method: 'GET', params: {} },
|
||||
post: { method: 'POST', params: {} },
|
||||
put: { method: 'POST', params: { id: '@id' } },
|
||||
del: { url: _apiUri + '/sites/:id/delete', method: 'POST', params: { id: '@id' } }
|
||||
});
|
||||
|
||||
_service.folders = $resource(_apiUri + '/folders/:id', {}, {
|
||||
get: { method: 'GET', params: { id: '@id' } },
|
||||
list: { method: 'GET', params: {} },
|
||||
post: { method: 'POST', params: {} },
|
||||
put: { method: 'POST', params: { id: '@id' } },
|
||||
del: { url: _apiUri + '/folders/:id/delete', method: 'POST', params: { id: '@id' } }
|
||||
});
|
||||
|
||||
_service.ciphers = $resource(_apiUri + '/ciphers/:id', {}, {
|
||||
get: { method: 'GET', params: { id: '@id' } },
|
||||
list: { method: 'GET', params: {} },
|
||||
'import': { url: _apiUri + '/ciphers/import', method: 'POST', params: {} },
|
||||
favorite: { url: _apiUri + '/ciphers/:id/favorite', method: 'POST', params: { id: '@id' } },
|
||||
del: { url: _apiUri + '/ciphers/:id/delete', method: 'POST', params: { id: '@id' } }
|
||||
});
|
||||
|
||||
_service.accounts = $resource(_apiUri + '/accounts', {}, {
|
||||
register: { url: _apiUri + '/accounts/register', method: 'POST', params: {} },
|
||||
emailToken: { url: _apiUri + '/accounts/email-token', method: 'POST', params: {} },
|
||||
email: { url: _apiUri + '/accounts/email', method: 'POST', params: {} },
|
||||
putPassword: { url: _apiUri + '/accounts/password', method: 'POST', params: {} },
|
||||
getProfile: { url: _apiUri + '/accounts/profile', method: 'GET', params: {} },
|
||||
putProfile: { url: _apiUri + '/accounts/profile', method: 'POST', params: {} },
|
||||
getTwoFactor: { url: _apiUri + '/accounts/two-factor', method: 'GET', params: {} },
|
||||
putTwoFactor: { url: _apiUri + '/accounts/two-factor', method: 'POST', params: {} },
|
||||
postTwoFactorRecover: { url: _apiUri + '/accounts/two-factor-recover', method: 'POST', params: {} },
|
||||
postPasswordHint: { url: _apiUri + '/accounts/password-hint', method: 'POST', params: {} },
|
||||
putSecurityStamp: { url: _apiUri + '/accounts/security-stamp', method: 'POST', params: {} },
|
||||
'import': { url: _apiUri + '/accounts/import', method: 'POST', params: {} },
|
||||
postDelete: { url: _apiUri + '/accounts/delete', method: 'POST', params: {} }
|
||||
});
|
||||
|
||||
_service.auth = $resource(_apiUri + '/auth', {}, {
|
||||
token: { url: _apiUri + '/auth/token', method: 'POST', params: {} },
|
||||
tokenTwoFactor: { url: _apiUri + '/auth/token/two-factor', method: 'POST', params: {} }
|
||||
});
|
||||
|
||||
return _service;
|
||||
});
|
||||
112
src/app/services/authService.js
Normal file
112
src/app/services/authService.js
Normal file
@@ -0,0 +1,112 @@
|
||||
angular
|
||||
.module('bit.services')
|
||||
|
||||
.factory('authService', function (cryptoService, apiService, tokenService, $q, jwtHelper) {
|
||||
var _service = {},
|
||||
_userProfile = null;
|
||||
|
||||
_service.logIn = function (email, masterPassword) {
|
||||
email = email.toLowerCase();
|
||||
var key = cryptoService.makeKey(masterPassword, email);
|
||||
|
||||
var request = {
|
||||
email: email,
|
||||
masterPasswordHash: cryptoService.hashPassword(masterPassword, key)
|
||||
};
|
||||
|
||||
var deferred = $q.defer();
|
||||
apiService.auth.token(request, function (response) {
|
||||
if (!response || !response.Token) {
|
||||
return;
|
||||
}
|
||||
|
||||
tokenService.setToken(response.Token);
|
||||
cryptoService.setKey(key);
|
||||
_service.setUserProfile(response.Profile);
|
||||
|
||||
deferred.resolve(response);
|
||||
}, function (error) {
|
||||
deferred.reject(error);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
_service.logInTwoFactor = function (code, provider) {
|
||||
var request = {
|
||||
code: code.replace(' ', ''),
|
||||
provider: provider
|
||||
};
|
||||
|
||||
var deferred = $q.defer();
|
||||
apiService.auth.tokenTwoFactor(request, function (response) {
|
||||
if (!response || !response.Token) {
|
||||
return;
|
||||
}
|
||||
|
||||
tokenService.setToken(response.Token);
|
||||
_service.setUserProfile(response.Profile);
|
||||
|
||||
deferred.resolve(response);
|
||||
}, function (error) {
|
||||
deferred.reject(error);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
_service.logOut = function () {
|
||||
tokenService.clearToken();
|
||||
cryptoService.clearKey();
|
||||
_userProfile = null;
|
||||
};
|
||||
|
||||
_service.getUserProfile = function () {
|
||||
if (!_userProfile) {
|
||||
_service.setUserProfile();
|
||||
}
|
||||
|
||||
return _userProfile;
|
||||
};
|
||||
|
||||
_service.setUserProfile = function (profile) {
|
||||
var token = tokenService.getToken();
|
||||
if (!token) {
|
||||
return;
|
||||
}
|
||||
|
||||
var decodedToken = jwtHelper.decodeToken(token);
|
||||
var twoFactor = decodedToken.authmethod === "TwoFactor";
|
||||
|
||||
_userProfile = {
|
||||
id: decodedToken.nameid,
|
||||
email: decodedToken.email,
|
||||
twoFactor: twoFactor
|
||||
};
|
||||
|
||||
if (!twoFactor && profile) {
|
||||
loadProfile(profile);
|
||||
}
|
||||
else if (!twoFactor && !profile) {
|
||||
apiService.accounts.getProfile({}, loadProfile);
|
||||
}
|
||||
};
|
||||
|
||||
function loadProfile(profile) {
|
||||
_userProfile.extended = {
|
||||
name: profile.Name,
|
||||
twoFactorEnabled: profile.TwoFactorEnabled,
|
||||
culture: profile.Culture
|
||||
};
|
||||
}
|
||||
|
||||
_service.isAuthenticated = function () {
|
||||
return _service.getUserProfile() !== null && !_service.getUserProfile().twoFactor;
|
||||
};
|
||||
|
||||
_service.isTwoFactorAuthenticated = function () {
|
||||
return _service.getUserProfile() !== null && _service.getUserProfile().twoFactor;
|
||||
};
|
||||
|
||||
return _service;
|
||||
});
|
||||
112
src/app/services/cipherService.js
Normal file
112
src/app/services/cipherService.js
Normal file
@@ -0,0 +1,112 @@
|
||||
angular
|
||||
.module('bit.services')
|
||||
|
||||
.factory('cipherService', function (cryptoService, apiService) {
|
||||
var _service = {};
|
||||
|
||||
_service.decryptSites = function (encryptedSites) {
|
||||
if (!encryptedSites) throw "encryptedSites is undefined or null";
|
||||
|
||||
var unencryptedSites = [];
|
||||
for (var i = 0; i < encryptedSites.length; i++) {
|
||||
unencryptedSites.push(_service.decryptSite(encryptedSites[i]));
|
||||
}
|
||||
|
||||
return unencryptedSites;
|
||||
};
|
||||
|
||||
_service.decryptSite = function (encryptedSite) {
|
||||
if (!encryptedSite) throw "encryptedSite is undefined or null";
|
||||
|
||||
var site = {
|
||||
id: encryptedSite.Id,
|
||||
'type': 1,
|
||||
folderId: encryptedSite.FolderId,
|
||||
favorite: encryptedSite.Favorite,
|
||||
name: cryptoService.decrypt(encryptedSite.Name),
|
||||
uri: encryptedSite.Uri && encryptedSite.Uri !== '' ? cryptoService.decrypt(encryptedSite.Uri) : null,
|
||||
username: encryptedSite.Username && encryptedSite.Username !== '' ? cryptoService.decrypt(encryptedSite.Username) : null,
|
||||
password: encryptedSite.Password && encryptedSite.Password !== '' ? cryptoService.decrypt(encryptedSite.Password) : null,
|
||||
notes: encryptedSite.Notes && encryptedSite.Notes !== '' ? cryptoService.decrypt(encryptedSite.Notes) : null
|
||||
};
|
||||
|
||||
if (encryptedSite.Folder) {
|
||||
site.folder = {
|
||||
name: cryptoService.decrypt(encryptedSite.Folder.Name)
|
||||
};
|
||||
}
|
||||
|
||||
return site;
|
||||
};
|
||||
|
||||
_service.decryptFolders = function (encryptedFolders) {
|
||||
if (!encryptedFolders) throw "encryptedFolders is undefined or null";
|
||||
|
||||
var unencryptedFolders = [];
|
||||
for (var i = 0; i < encryptedFolders.length; i++) {
|
||||
unencryptedFolders.push(_service.decryptFolder(encryptedFolders[i]));
|
||||
}
|
||||
|
||||
return unencryptedFolders;
|
||||
};
|
||||
|
||||
_service.decryptFolder = function (encryptedFolder) {
|
||||
if (!encryptedFolder) throw "encryptedFolder is undefined or null";
|
||||
|
||||
return {
|
||||
id: encryptedFolder.Id,
|
||||
'type': 0,
|
||||
name: cryptoService.decrypt(encryptedFolder.Name)
|
||||
};
|
||||
};
|
||||
|
||||
_service.encryptSites = function (unencryptedSites, key) {
|
||||
if (!unencryptedSites) throw "unencryptedSites is undefined or null";
|
||||
|
||||
var encryptedSites = [];
|
||||
for (var i = 0; i < unencryptedSites.length; i++) {
|
||||
encryptedSites.push(_service.encryptSite(unencryptedSites[i], key));
|
||||
}
|
||||
|
||||
return encryptedSites;
|
||||
};
|
||||
|
||||
_service.encryptSite = function (unencryptedSite, key) {
|
||||
if (!unencryptedSite) throw "unencryptedSite is undefined or null";
|
||||
|
||||
return {
|
||||
id: unencryptedSite.id,
|
||||
'type': 1,
|
||||
folderId: unencryptedSite.folderId === '' ? null : unencryptedSite.folderId,
|
||||
favorite: unencryptedSite.favorite !== null ? unencryptedSite.favorite : false,
|
||||
uri: !unencryptedSite.uri || unencryptedSite.uri === '' ? null : cryptoService.encrypt(unencryptedSite.uri, key),
|
||||
name: cryptoService.encrypt(unencryptedSite.name, key),
|
||||
username: !unencryptedSite.username || unencryptedSite.username === '' ? null : cryptoService.encrypt(unencryptedSite.username, key),
|
||||
password: !unencryptedSite.password || unencryptedSite.password === '' ? null : cryptoService.encrypt(unencryptedSite.password, key),
|
||||
notes: !unencryptedSite.notes || unencryptedSite.notes === '' ? null : cryptoService.encrypt(unencryptedSite.notes, key)
|
||||
};
|
||||
};
|
||||
|
||||
_service.encryptFolders = function (unencryptedFolders, key) {
|
||||
if (!unencryptedFolders) throw "unencryptedFolders is undefined or null";
|
||||
|
||||
var encryptedFolders = [];
|
||||
for (var i = 0; i < unencryptedFolders.length; i++) {
|
||||
encryptedFolders.push(_service.encryptFolder(unencryptedFolders[i], key));
|
||||
}
|
||||
|
||||
return encryptedFolders;
|
||||
};
|
||||
|
||||
_service.encryptFolder = function (unencryptedFolder, key) {
|
||||
if (!unencryptedFolder) throw "unencryptedFolder is undefined or null";
|
||||
|
||||
return {
|
||||
id: unencryptedFolder.id,
|
||||
'type': 0,
|
||||
name: cryptoService.encrypt(unencryptedFolder.name, key)
|
||||
};
|
||||
};
|
||||
|
||||
return _service;
|
||||
});
|
||||
114
src/app/services/cryptoService.js
Normal file
114
src/app/services/cryptoService.js
Normal file
@@ -0,0 +1,114 @@
|
||||
angular
|
||||
.module('bit.services')
|
||||
|
||||
.factory('cryptoService', function ($sessionStorage) {
|
||||
var _service = {},
|
||||
_key,
|
||||
_b64Key,
|
||||
_aes;
|
||||
|
||||
sjcl.beware["CBC mode is dangerous because it doesn't protect message integrity."]();
|
||||
|
||||
_service.setKey = function (key) {
|
||||
_key = key;
|
||||
$sessionStorage.key = sjcl.codec.base64.fromBits(key);
|
||||
};
|
||||
|
||||
_service.getKey = function (b64) {
|
||||
if (b64 && b64 === true && _b64Key) {
|
||||
return _b64Key;
|
||||
}
|
||||
else if (!b64 && _key) {
|
||||
return _key;
|
||||
}
|
||||
|
||||
if ($sessionStorage.key) {
|
||||
_key = sjcl.codec.base64.toBits($sessionStorage.key);
|
||||
}
|
||||
|
||||
if (b64 && b64 === true) {
|
||||
_b64Key = sjcl.codec.base64.fromBits(_key);
|
||||
return _b64Key;
|
||||
}
|
||||
|
||||
return _key;
|
||||
};
|
||||
|
||||
_service.clearKey = function () {
|
||||
_key = _b64Key = _aes = null;
|
||||
delete $sessionStorage.key;
|
||||
};
|
||||
|
||||
_service.makeKey = function (password, salt, b64) {
|
||||
var key = sjcl.misc.pbkdf2(password, salt, 5000, 256, null);
|
||||
|
||||
if (b64 && b64 === true) {
|
||||
return sjcl.codec.base64.fromBits(key);
|
||||
}
|
||||
|
||||
return key;
|
||||
};
|
||||
|
||||
_service.hashPassword = function (password, key) {
|
||||
if (!key) {
|
||||
key = _service.getKey();
|
||||
}
|
||||
|
||||
if (!password || !key) {
|
||||
throw 'Invalid parameters.';
|
||||
}
|
||||
|
||||
var hashBits = sjcl.misc.pbkdf2(key, password, 1, 256, null);
|
||||
return sjcl.codec.base64.fromBits(hashBits);
|
||||
};
|
||||
|
||||
_service.getAes = function () {
|
||||
if (!_aes && _service.getKey()) {
|
||||
_aes = new sjcl.cipher.aes(_service.getKey());
|
||||
}
|
||||
|
||||
return _aes;
|
||||
};
|
||||
|
||||
_service.encrypt = function (plaintextValue, key) {
|
||||
if (!_service.getKey() && !key) {
|
||||
throw 'Encryption key unavailable.';
|
||||
}
|
||||
|
||||
if (!key) {
|
||||
key = _service.getKey();
|
||||
}
|
||||
|
||||
var response = {};
|
||||
var params = {
|
||||
mode: "cbc",
|
||||
iv: sjcl.random.randomWords(4, 10)
|
||||
};
|
||||
|
||||
var ctJson = sjcl.encrypt(key, plaintextValue, params, response);
|
||||
|
||||
var ct = ctJson.match(/"ct":"([^"]*)"/)[1];
|
||||
var iv = sjcl.codec.base64.fromBits(response.iv);
|
||||
|
||||
return iv + "|" + ct;
|
||||
};
|
||||
|
||||
_service.decrypt = function (encValue) {
|
||||
if (!_service.getAes()) {
|
||||
throw 'AES encryption unavailable.';
|
||||
}
|
||||
|
||||
var encPieces = encValue.split('|');
|
||||
if (encPieces.length !== 2) {
|
||||
return '';
|
||||
}
|
||||
|
||||
var ivBits = sjcl.codec.base64.toBits(encPieces[0]);
|
||||
var ctBits = sjcl.codec.base64.toBits(encPieces[1]);
|
||||
|
||||
var decBits = sjcl.mode.cbc.decrypt(_service.getAes(), ctBits, ivBits, null);
|
||||
return sjcl.codec.utf8String.fromBits(decBits);
|
||||
};
|
||||
|
||||
return _service;
|
||||
});
|
||||
986
src/app/services/importService.js
Normal file
986
src/app/services/importService.js
Normal file
@@ -0,0 +1,986 @@
|
||||
angular
|
||||
.module('bit.services')
|
||||
|
||||
.factory('importService', function () {
|
||||
var _service = {};
|
||||
|
||||
_service.import = function (source, file, success, error) {
|
||||
if (!file) {
|
||||
error();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (source) {
|
||||
case 'local':
|
||||
importLocal(file, success, error);
|
||||
break;
|
||||
case 'lastpass':
|
||||
importLastPass(file, success, error);
|
||||
break;
|
||||
case 'safeincloudcsv':
|
||||
importSafeInCloudCsv(file, success, error);
|
||||
break;
|
||||
case 'safeincloudxml':
|
||||
importSafeInCloudXml(file, success, error);
|
||||
break;
|
||||
case 'keypassxml':
|
||||
importKeyPassXml(file, success, error);
|
||||
break;
|
||||
case 'padlockcsv':
|
||||
importPadlockCsv(file, success, error);
|
||||
break;
|
||||
case '1password1pif':
|
||||
import1Password1Pif(file, success, error);
|
||||
break;
|
||||
case 'chromecsv':
|
||||
importChromeCsv(file, success, error);
|
||||
break;
|
||||
case 'firefoxpasswordexportercsvxml':
|
||||
importFirefoxPasswordExporterCsvXml(file, success, error);
|
||||
break;
|
||||
case 'upmcsv':
|
||||
importUpmCsv(file, success, error);
|
||||
break;
|
||||
case 'keepercsv':
|
||||
importKeeperCsv(file, success, error);
|
||||
break;
|
||||
case 'passworddragonxml':
|
||||
importPasswordDragonXml(file, success, error);
|
||||
break;
|
||||
default:
|
||||
error();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
function trimUri(uri) {
|
||||
if (uri.length > 1000) {
|
||||
return uri.substring(0, 1000);
|
||||
}
|
||||
|
||||
return uri;
|
||||
}
|
||||
|
||||
function parseCsvErrors(results) {
|
||||
if (results.errors && results.errors.length) {
|
||||
for (var i = 0; i < results.errors.length; i++) {
|
||||
console.warn('Error parsing row ' + results.errors[i].row + ': ' + results.errors[i].message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function importLocal(file, success, error) {
|
||||
Papa.parse(file, {
|
||||
header: true,
|
||||
encoding: 'UTF-8',
|
||||
complete: function (results) {
|
||||
parseCsvErrors(results);
|
||||
|
||||
var folders = [],
|
||||
sites = [],
|
||||
folderRelationships = [];
|
||||
|
||||
angular.forEach(results.data, function (value, key) {
|
||||
var folderIndex = folders.length,
|
||||
siteIndex = sites.length,
|
||||
hasFolder = value.folder && value.folder !== '',
|
||||
addFolder = hasFolder;
|
||||
|
||||
if (hasFolder) {
|
||||
for (var i = 0; i < folders.length; i++) {
|
||||
if (folders[i].name === value.folder) {
|
||||
addFolder = false;
|
||||
folderIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sites.push({
|
||||
favorite: value.favorite !== null ? value.favorite : false,
|
||||
uri: value.uri && value.uri !== '' ? trimUri(value.uri) : null,
|
||||
username: value.username && value.username !== '' ? value.username : null,
|
||||
password: value.password && value.password !== '' ? value.password : null,
|
||||
notes: value.notes && value.notes !== '' ? value.notes : null,
|
||||
name: value.name && value.name !== '' ? value.name : '--',
|
||||
});
|
||||
|
||||
if (addFolder) {
|
||||
folders.push({
|
||||
name: value.folder
|
||||
});
|
||||
}
|
||||
|
||||
if (hasFolder) {
|
||||
var relationship = {
|
||||
key: siteIndex,
|
||||
value: folderIndex
|
||||
};
|
||||
folderRelationships.push(relationship);
|
||||
}
|
||||
});
|
||||
|
||||
success(folders, sites, folderRelationships);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function importLastPass(file, success, error) {
|
||||
if (file.type === 'text/html') {
|
||||
var reader = new FileReader();
|
||||
reader.readAsText(file, 'utf-8');
|
||||
reader.onload = function (evt) {
|
||||
var doc = $(evt.target.result);
|
||||
var pre = doc.find('pre');
|
||||
var csv, results;
|
||||
|
||||
if (pre.length === 1) {
|
||||
csv = pre.text().trim();
|
||||
results = Papa.parse(csv, {
|
||||
header: true,
|
||||
encoding: 'UTF-8'
|
||||
});
|
||||
parseData(results.data);
|
||||
}
|
||||
else {
|
||||
var foundPre = false;
|
||||
for (var i = 0; i < doc.length; i++) {
|
||||
if (doc[i].tagName.toLowerCase() === 'pre') {
|
||||
foundPre = true;
|
||||
csv = doc[i].outerText.trim();
|
||||
results = Papa.parse(csv, {
|
||||
header: true,
|
||||
encoding: 'UTF-8'
|
||||
});
|
||||
parseData(results.data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundPre) {
|
||||
error();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
reader.onerror = function (evt) {
|
||||
error();
|
||||
};
|
||||
}
|
||||
else {
|
||||
Papa.parse(file, {
|
||||
header: true,
|
||||
encoding: 'UTF-8',
|
||||
complete: function (results) {
|
||||
parseCsvErrors(results);
|
||||
parseData(results.data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function parseData(data) {
|
||||
var folders = [],
|
||||
sites = [],
|
||||
siteRelationships = [],
|
||||
badDataSites = 0;
|
||||
|
||||
angular.forEach(data, function (value, key) {
|
||||
var folderIndex = folders.length,
|
||||
siteIndex = sites.length,
|
||||
hasFolder = value.grouping && value.grouping !== '' && value.grouping !== '(none)',
|
||||
addFolder = hasFolder;
|
||||
|
||||
if (hasFolder) {
|
||||
for (var i = 0; i < folders.length; i++) {
|
||||
if (folders[i].name === value.grouping) {
|
||||
addFolder = false;
|
||||
folderIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((!value.name || value.name === '') && (!value.password || value.password === '')) {
|
||||
badDataSites++;
|
||||
}
|
||||
|
||||
sites.push({
|
||||
favorite: value.fav === '1',
|
||||
uri: value.url && value.url !== '' ? trimUri(value.url) : null,
|
||||
username: value.username && value.username !== '' ? value.username : null,
|
||||
password: value.password && value.password !== '' ? value.password : null,
|
||||
notes: value.extra && value.extra !== '' ? value.extra : null,
|
||||
name: value.name && value.name !== '' ? value.name : '--',
|
||||
});
|
||||
|
||||
if (addFolder) {
|
||||
folders.push({
|
||||
name: value.grouping
|
||||
});
|
||||
}
|
||||
|
||||
if (hasFolder) {
|
||||
var relationship = {
|
||||
key: siteIndex,
|
||||
value: folderIndex
|
||||
};
|
||||
siteRelationships.push(relationship);
|
||||
}
|
||||
});
|
||||
|
||||
if (badDataSites && badDataSites > (data.length / 2)) {
|
||||
error('CSV data is not formatted correctly from LastPass. Please check your import file and try again.');
|
||||
}
|
||||
else {
|
||||
success(folders, sites, siteRelationships);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function importSafeInCloudCsv(file, success, error) {
|
||||
Papa.parse(file, {
|
||||
header: true,
|
||||
encoding: 'UTF-8',
|
||||
complete: function (results) {
|
||||
parseCsvErrors(results);
|
||||
|
||||
var folders = [],
|
||||
sites = [],
|
||||
siteRelationships = [];
|
||||
|
||||
angular.forEach(results.data, function (value, key) {
|
||||
sites.push({
|
||||
favorite: false,
|
||||
uri: value.URL && value.URL !== '' ? trimUri(value.URL) : null,
|
||||
username: value.Login && value.Login !== '' ? value.Login : null,
|
||||
password: value.Password && value.Password !== '' ? value.Password : null,
|
||||
notes: value.Notes && value.Notes !== '' ? value.Notes : null,
|
||||
name: value.Title && value.Title !== '' ? value.Title : '--',
|
||||
});
|
||||
});
|
||||
|
||||
success(folders, sites, siteRelationships);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function importSafeInCloudXml(file, success, error) {
|
||||
var folders = [],
|
||||
sites = [],
|
||||
siteRelationships = [],
|
||||
foldersIndex = [];
|
||||
|
||||
var i = 0,
|
||||
j = 0;
|
||||
|
||||
var reader = new FileReader();
|
||||
reader.readAsText(file, 'utf-8');
|
||||
reader.onload = function (evt) {
|
||||
var xmlDoc = $.parseXML(evt.target.result),
|
||||
xml = $(xmlDoc);
|
||||
|
||||
var db = xml.find('database');
|
||||
if (db.length) {
|
||||
var labels = db.find('> label');
|
||||
if (labels.length) {
|
||||
for (i = 0; i < labels.length; i++) {
|
||||
var label = $(labels[i]);
|
||||
foldersIndex[label.attr('id')] = folders.length;
|
||||
folders.push({
|
||||
name: label.attr('name')
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var cards = db.find('> card');
|
||||
if (cards.length) {
|
||||
for (i = 0; i < cards.length; i++) {
|
||||
var card = $(cards[i]);
|
||||
if (card.attr('template') === 'true') {
|
||||
continue;
|
||||
}
|
||||
|
||||
var site = {
|
||||
favorite: false,
|
||||
uri: null,
|
||||
username: null,
|
||||
password: null,
|
||||
notes: null,
|
||||
name: card.attr('title'),
|
||||
};
|
||||
|
||||
var fields = card.find('> field');
|
||||
for (j = 0; j < fields.length; j++) {
|
||||
var field = $(fields[j]);
|
||||
|
||||
var text = field.text();
|
||||
var type = field.attr('type');
|
||||
|
||||
if (text && text !== '') {
|
||||
if (type === 'login') {
|
||||
site.username = text;
|
||||
}
|
||||
else if (type === 'password') {
|
||||
site.password = text;
|
||||
}
|
||||
else if (type === 'notes') {
|
||||
site.notes = text;
|
||||
}
|
||||
else if (type === 'website') {
|
||||
site.uri = trimUri(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sites.push(site);
|
||||
|
||||
labels = card.find('> label_id');
|
||||
if (labels.length) {
|
||||
var labelId = $(labels[0]).text();
|
||||
var folderIndex = foldersIndex[labelId];
|
||||
if (labelId !== null && labelId !== '' && folderIndex !== null) {
|
||||
siteRelationships.push({
|
||||
key: sites.length - 1,
|
||||
value: folderIndex
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
success(folders, sites, siteRelationships);
|
||||
}
|
||||
else {
|
||||
error();
|
||||
}
|
||||
};
|
||||
|
||||
reader.onerror = function (evt) {
|
||||
error();
|
||||
};
|
||||
}
|
||||
|
||||
function importPadlockCsv(file, success, error) {
|
||||
Papa.parse(file, {
|
||||
encoding: 'UTF-8',
|
||||
complete: function (results) {
|
||||
parseCsvErrors(results);
|
||||
|
||||
var folders = [],
|
||||
sites = [],
|
||||
folderRelationships = [];
|
||||
|
||||
var customFieldHeaders = [];
|
||||
|
||||
// CSV index ref: 0 = name, 1 = category, 2 = username, 3 = password, 4+ = custom fields
|
||||
|
||||
var i = 0,
|
||||
j = 0;
|
||||
|
||||
for (i = 0; i < results.data.length; i++) {
|
||||
var value = results.data[i];
|
||||
if (i === 0) {
|
||||
// header row
|
||||
for (j = 4; j < value.length; j++) {
|
||||
customFieldHeaders.push(value[j]);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
var folderIndex = folders.length,
|
||||
siteIndex = sites.length,
|
||||
hasFolder = value[1] && value[1] !== '',
|
||||
addFolder = hasFolder;
|
||||
|
||||
if (hasFolder) {
|
||||
for (j = 0; j < folders.length; j++) {
|
||||
if (folders[j].name === value[1]) {
|
||||
addFolder = false;
|
||||
folderIndex = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var site = {
|
||||
favorite: false,
|
||||
uri: null,
|
||||
username: value[2] && value[2] !== '' ? value[2] : null,
|
||||
password: value[3] && value[3] !== '' ? value[3] : null,
|
||||
notes: null,
|
||||
name: value[0] && value[0] !== '' ? value[0] : '--',
|
||||
};
|
||||
|
||||
if (customFieldHeaders.length) {
|
||||
for (j = 4; j < value.length; j++) {
|
||||
var cf = value[j];
|
||||
if (!cf || cf === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
var cfHeader = customFieldHeaders[j - 4];
|
||||
if (cfHeader.toLowerCase() === 'url' || cfHeader.toLowerCase() === 'uri') {
|
||||
site.uri = trimUri(cf);
|
||||
}
|
||||
else {
|
||||
if (site.notes === null) {
|
||||
site.notes = '';
|
||||
}
|
||||
|
||||
site.notes += cfHeader + ': ' + cf + '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sites.push(site);
|
||||
|
||||
if (addFolder) {
|
||||
folders.push({
|
||||
name: value[1]
|
||||
});
|
||||
}
|
||||
|
||||
if (hasFolder) {
|
||||
folderRelationships.push({
|
||||
key: siteIndex,
|
||||
value: folderIndex
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
success(folders, sites, folderRelationships);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function importKeyPassXml(file, success, error) {
|
||||
var folders = [],
|
||||
sites = [],
|
||||
siteRelationships = [];
|
||||
|
||||
var reader = new FileReader();
|
||||
reader.readAsText(file, 'utf-8');
|
||||
reader.onload = function (evt) {
|
||||
var xmlDoc = $.parseXML(evt.target.result),
|
||||
xml = $(xmlDoc);
|
||||
|
||||
var root = xml.find('Root');
|
||||
if (root.length) {
|
||||
var group = root.find('> Group');
|
||||
if (group.length) {
|
||||
traverse($(group[0]), true, '');
|
||||
success(folders, sites, siteRelationships);
|
||||
}
|
||||
}
|
||||
else {
|
||||
error();
|
||||
}
|
||||
};
|
||||
|
||||
reader.onerror = function (evt) {
|
||||
error();
|
||||
};
|
||||
|
||||
function traverse(node, isRootNode, groupNamePrefix) {
|
||||
var nodeEntries = [];
|
||||
var folderIndex = folders.length;
|
||||
var groupName = groupNamePrefix;
|
||||
|
||||
if (!isRootNode) {
|
||||
if (groupName !== '') {
|
||||
groupName += ' > ';
|
||||
}
|
||||
groupName += node.find('> Name').text();
|
||||
folders.push({
|
||||
name: groupName
|
||||
});
|
||||
}
|
||||
|
||||
var entries = node.find('> Entry');
|
||||
if (entries.length) {
|
||||
for (var i = 0; i < entries.length; i++) {
|
||||
var entry = $(entries[i]);
|
||||
var siteIndex = sites.length;
|
||||
var site = {
|
||||
favorite: false,
|
||||
uri: null,
|
||||
username: null,
|
||||
password: null,
|
||||
notes: null,
|
||||
name: null
|
||||
};
|
||||
|
||||
var entryStrings = entry.find('> String');
|
||||
for (var j = 0; j < entryStrings.length; j++) {
|
||||
var entryString = $(entryStrings[j]);
|
||||
|
||||
var key = entryString.find('> Key').text();
|
||||
var value = entryString.find('> Value').text();
|
||||
if (value === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (key) {
|
||||
case 'URL':
|
||||
site.uri = trimUri(value);
|
||||
break;
|
||||
case 'UserName':
|
||||
site.username = value;
|
||||
break;
|
||||
case 'Password':
|
||||
site.password = value;
|
||||
break;
|
||||
case 'Title':
|
||||
site.name = value;
|
||||
break;
|
||||
case 'Notes':
|
||||
site.notes = site.notes === null ? value + '\n' : site.notes + value + '\n';
|
||||
break;
|
||||
default:
|
||||
// other custom fields
|
||||
site.notes = site.notes === null ? key + ': ' + value + '\n'
|
||||
: site.notes + key + ': ' + value + '\n';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (site.name === null) {
|
||||
site.name = '--';
|
||||
}
|
||||
|
||||
sites.push(site);
|
||||
|
||||
if (!isRootNode) {
|
||||
siteRelationships.push({
|
||||
key: siteIndex,
|
||||
value: folderIndex
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var groups = node.find('> Group');
|
||||
if (groups.length) {
|
||||
for (var k = 0; k < groups.length; k++) {
|
||||
traverse($(groups[k]), false, groupName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function import1Password1Pif(file, success, error) {
|
||||
var folders = [],
|
||||
sites = [],
|
||||
siteRelationships = [];
|
||||
|
||||
var i = 0,
|
||||
j = 0;
|
||||
|
||||
var reader = new FileReader();
|
||||
reader.readAsText(file, 'utf-8');
|
||||
reader.onload = function (evt) {
|
||||
var fileContent = evt.target.result;
|
||||
var fileLines = fileContent.split(/(?:\r\n|\r|\n)/);
|
||||
|
||||
for (i = 0; i < fileLines.length; i++) {
|
||||
var line = fileLines[i];
|
||||
if (!line.length || line[0] !== '{') {
|
||||
continue;
|
||||
}
|
||||
|
||||
var item = JSON.parse(line);
|
||||
if (item.typeName !== 'webforms.WebForm') {
|
||||
continue;
|
||||
}
|
||||
|
||||
var site = {
|
||||
favorite: item.openContents && item.openContents.faveIndex ? true : false,
|
||||
uri: item.location && item.location !== '' ? trimUri(item.location) : null,
|
||||
username: null,
|
||||
password: null,
|
||||
notes: null,
|
||||
name: item.title && item.title !== '' ? item.title : '--',
|
||||
};
|
||||
|
||||
if (item.secureContents) {
|
||||
if (item.secureContents.notesPlain && item.secureContents.notesPlain !== '') {
|
||||
site.notes = item.secureContents.notesPlain;
|
||||
}
|
||||
|
||||
if (item.secureContents.fields) {
|
||||
for (j = 0; j < item.secureContents.fields.length; j++) {
|
||||
var field = item.secureContents.fields[j];
|
||||
if (field.designation === 'username') {
|
||||
site.username = field.value;
|
||||
}
|
||||
else if (field.designation === 'password') {
|
||||
site.password = field.value;
|
||||
}
|
||||
else {
|
||||
if (site.notes === null) {
|
||||
site.notes = '';
|
||||
}
|
||||
else {
|
||||
site.notes += '\n';
|
||||
}
|
||||
|
||||
site.notes += (field.name + ': ' + field.value + '\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sites.push(site);
|
||||
}
|
||||
|
||||
success(folders, sites, siteRelationships);
|
||||
};
|
||||
|
||||
reader.onerror = function (evt) {
|
||||
error();
|
||||
};
|
||||
}
|
||||
|
||||
function importChromeCsv(file, success, error) {
|
||||
Papa.parse(file, {
|
||||
header: true,
|
||||
encoding: 'UTF-8',
|
||||
complete: function (results) {
|
||||
parseCsvErrors(results);
|
||||
|
||||
var folders = [],
|
||||
sites = [],
|
||||
siteRelationships = [];
|
||||
|
||||
angular.forEach(results.data, function (value, key) {
|
||||
sites.push({
|
||||
favorite: false,
|
||||
uri: value.url && value.url !== '' ? trimUri(value.url) : null,
|
||||
username: value.username && value.username !== '' ? value.username : null,
|
||||
password: value.password && value.password !== '' ? value.password : null,
|
||||
notes: null,
|
||||
name: value.name && value.name !== '' ? value.name : '--',
|
||||
});
|
||||
});
|
||||
|
||||
success(folders, sites, siteRelationships);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function importFirefoxPasswordExporterCsvXml(file, success, error) {
|
||||
var folders = [],
|
||||
sites = [],
|
||||
siteRelationships = [];
|
||||
|
||||
function getNameFromHost(host) {
|
||||
var name = '--';
|
||||
try {
|
||||
if (host && host !== '') {
|
||||
var parser = document.createElement('a');
|
||||
parser.href = host;
|
||||
if (parser.hostname) {
|
||||
name = parser.hostname;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
if (file.type === 'text/xml') {
|
||||
var reader = new FileReader();
|
||||
reader.readAsText(file, 'utf-8');
|
||||
reader.onload = function (evt) {
|
||||
var xmlDoc = $.parseXML(evt.target.result),
|
||||
xml = $(xmlDoc);
|
||||
|
||||
var entries = xml.find('entry');
|
||||
for (var i = 0; i < entries.length; i++) {
|
||||
var entry = $(entries[i]);
|
||||
if (!entry) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var host = entry.attr('host'),
|
||||
user = entry.attr('user'),
|
||||
password = entry.attr('password');
|
||||
|
||||
sites.push({
|
||||
favorite: false,
|
||||
uri: host && host !== '' ? trimUri(host) : null,
|
||||
username: user && user !== '' ? user : null,
|
||||
password: password && password !== '' ? password : null,
|
||||
notes: null,
|
||||
name: getNameFromHost(host),
|
||||
});
|
||||
}
|
||||
|
||||
success(folders, sites, siteRelationships);
|
||||
};
|
||||
|
||||
reader.onerror = function (evt) {
|
||||
error();
|
||||
};
|
||||
}
|
||||
else {
|
||||
// currently bugged due to the comment
|
||||
// ref: https://github.com/mholt/PapaParse/issues/351
|
||||
|
||||
error('Only .xml exports are supported.');
|
||||
return;
|
||||
|
||||
//Papa.parse(file, {
|
||||
// comments: '#',
|
||||
// header: true,
|
||||
// encoding: 'UTF-8',
|
||||
// complete: function (results) {
|
||||
// parseCsvErrors(results);
|
||||
|
||||
// angular.forEach(results.data, function (value, key) {
|
||||
// sites.push({
|
||||
// favorite: false,
|
||||
// uri: value.hostname && value.hostname !== '' ? trimUri(value.hostname) : null,
|
||||
// username: value.username && value.username !== '' ? value.username : null,
|
||||
// password: value.password && value.password !== '' ? value.password : null,
|
||||
// notes: null,
|
||||
// name: getNameFromHost(value.hostname),
|
||||
// });
|
||||
// });
|
||||
|
||||
// success(folders, sites, siteRelationships);
|
||||
// }
|
||||
//});
|
||||
}
|
||||
}
|
||||
|
||||
function importUpmCsv(file, success, error) {
|
||||
Papa.parse(file, {
|
||||
encoding: 'UTF-8',
|
||||
complete: function (results) {
|
||||
parseCsvErrors(results);
|
||||
|
||||
var folders = [],
|
||||
sites = [],
|
||||
siteRelationships = [];
|
||||
|
||||
angular.forEach(results.data, function (value, key) {
|
||||
if (value.length === 5) {
|
||||
sites.push({
|
||||
favorite: false,
|
||||
uri: value[3] && value[3] !== '' ? trimUri(value[3]) : null,
|
||||
username: value[1] && value[1] !== '' ? value[1] : null,
|
||||
password: value[2] && value[2] !== '' ? value[2] : null,
|
||||
notes: value[4] && value[4] !== '' ? value[4] : null,
|
||||
name: value[0] && value[0] !== '' ? value[0] : '--',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
success(folders, sites, siteRelationships);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function importKeeperCsv(file, success, error) {
|
||||
Papa.parse(file, {
|
||||
encoding: 'UTF-8',
|
||||
complete: function (results) {
|
||||
parseCsvErrors(results);
|
||||
|
||||
var folders = [],
|
||||
sites = [],
|
||||
folderRelationships = [];
|
||||
|
||||
angular.forEach(results.data, function (value, key) {
|
||||
if (value.length >= 6) {
|
||||
var folderIndex = folders.length,
|
||||
siteIndex = sites.length,
|
||||
hasFolder = value[0] && value[0] !== '',
|
||||
addFolder = hasFolder,
|
||||
i = 0;
|
||||
|
||||
if (hasFolder) {
|
||||
for (i = 0; i < folders.length; i++) {
|
||||
if (folders[i].name === value[0]) {
|
||||
addFolder = false;
|
||||
folderIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var site = {
|
||||
favorite: false,
|
||||
uri: value[4] && value[4] !== '' ? trimUri(value[4]) : null,
|
||||
username: value[2] && value[2] !== '' ? value[2] : null,
|
||||
password: value[3] && value[3] !== '' ? value[3] : null,
|
||||
notes: value[5] && value[5] !== '' ? value[5] : null,
|
||||
name: value[1] && value[1] !== '' ? value[1] : '--',
|
||||
};
|
||||
|
||||
if (value.length > 6) {
|
||||
// we have some custom fields. add them to notes.
|
||||
|
||||
if (site.notes === null) {
|
||||
site.notes = '';
|
||||
}
|
||||
else {
|
||||
site.notes += '\n';
|
||||
}
|
||||
|
||||
for (i = 6; i < value.length; i = i + 2) {
|
||||
var cfName = value[i];
|
||||
var cfValue = value[i + 1];
|
||||
site.notes += (cfName + ': ' + cfValue + '\n');
|
||||
}
|
||||
}
|
||||
|
||||
sites.push(site);
|
||||
|
||||
if (addFolder) {
|
||||
folders.push({
|
||||
name: value[0]
|
||||
});
|
||||
}
|
||||
|
||||
if (hasFolder) {
|
||||
var relationship = {
|
||||
key: siteIndex,
|
||||
value: folderIndex
|
||||
};
|
||||
folderRelationships.push(relationship);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
success(folders, sites, folderRelationships);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function importPasswordDragonXml(file, success, error) {
|
||||
var folders = [],
|
||||
sites = [],
|
||||
folderRelationships = [],
|
||||
foldersIndex = [],
|
||||
j = 0;
|
||||
|
||||
var reader = new FileReader();
|
||||
reader.readAsText(file, 'utf-8');
|
||||
reader.onload = function (evt) {
|
||||
var xmlDoc = $.parseXML(evt.target.result),
|
||||
xml = $(xmlDoc);
|
||||
|
||||
var pwManager = xml.find('PasswordManager');
|
||||
if (pwManager.length) {
|
||||
var records = pwManager.find('> record');
|
||||
if (records.length) {
|
||||
for (var i = 0; i < records.length; i++) {
|
||||
var record = $(records[i]);
|
||||
|
||||
var accountNameNode = record.find('> Account-Name'),
|
||||
accountName = accountNameNode.length ? $(accountNameNode) : null,
|
||||
userIdNode = record.find('> User-Id'),
|
||||
userId = userIdNode.length ? $(userIdNode) : null,
|
||||
passwordNode = record.find('> Password'),
|
||||
password = passwordNode.length ? $(passwordNode) : null,
|
||||
urlNode = record.find('> URL'),
|
||||
url = urlNode.length ? $(urlNode) : null,
|
||||
notesNode = record.find('> Notes'),
|
||||
notes = notesNode.length ? $(notesNode) : null,
|
||||
categoryNode = record.find('> Category'),
|
||||
category = categoryNode.length ? $(categoryNode) : null,
|
||||
categoryText = category ? category.text() : null;
|
||||
|
||||
var folderIndex = folders.length,
|
||||
siteIndex = sites.length,
|
||||
hasFolder = categoryText && categoryText !== '' && categoryText !== 'Unfiled',
|
||||
addFolder = hasFolder;
|
||||
|
||||
if (hasFolder) {
|
||||
for (j = 0; j < folders.length; j++) {
|
||||
if (folders[j].name === categoryText) {
|
||||
addFolder = false;
|
||||
folderIndex = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var site = {
|
||||
favorite: false,
|
||||
uri: url && url.text() !== '' ? trimUri(url.text()) : null,
|
||||
username: userId && userId.text() !== '' ? userId.text() : null,
|
||||
password: password && password.text() !== '' ? password.text() : null,
|
||||
notes: notes && notes.text() !== '' ? notes.text() : null,
|
||||
name: accountName && accountName.text() !== '' ? accountName.text() : '--',
|
||||
};
|
||||
|
||||
var attributesSelector = '';
|
||||
for (j = 1; j <= 10; j++) {
|
||||
attributesSelector += '> Attribute-' + j;
|
||||
if (j < 10) {
|
||||
attributesSelector += ', ';
|
||||
}
|
||||
}
|
||||
|
||||
var attributes = record.find(attributesSelector);
|
||||
if (attributes.length) {
|
||||
// we have some attributes. add them to notes.
|
||||
for (j = 0; j < attributes.length; j++) {
|
||||
var attr = $(attributes[j]),
|
||||
attrName = attr.prop('tagName'),
|
||||
attrValue = attr.text();
|
||||
|
||||
if (!attrValue || attrValue === '' || attrValue === 'null') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (site.notes === null) {
|
||||
site.notes = '';
|
||||
}
|
||||
else {
|
||||
site.notes += '\n';
|
||||
}
|
||||
|
||||
site.notes += (attrName + ': ' + attrValue);
|
||||
}
|
||||
}
|
||||
|
||||
sites.push(site);
|
||||
|
||||
if (addFolder) {
|
||||
folders.push({
|
||||
name: categoryText
|
||||
});
|
||||
}
|
||||
|
||||
if (hasFolder) {
|
||||
var relationship = {
|
||||
key: siteIndex,
|
||||
value: folderIndex
|
||||
};
|
||||
folderRelationships.push(relationship);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
success(folders, sites, folderRelationships);
|
||||
}
|
||||
else {
|
||||
error();
|
||||
}
|
||||
};
|
||||
|
||||
reader.onerror = function (evt) {
|
||||
error();
|
||||
};
|
||||
}
|
||||
|
||||
return _service;
|
||||
});
|
||||
136
src/app/services/passwordService.js
Normal file
136
src/app/services/passwordService.js
Normal file
@@ -0,0 +1,136 @@
|
||||
angular
|
||||
.module('bit.services')
|
||||
|
||||
.factory('passwordService', function () {
|
||||
var _service = {};
|
||||
|
||||
_service.generatePassword = function (options) {
|
||||
var defaults = {
|
||||
length: 10,
|
||||
ambiguous: false,
|
||||
number: true,
|
||||
minNumber: 1,
|
||||
uppercase: true,
|
||||
minUppercase: 1,
|
||||
lowercase: true,
|
||||
minLowercase: 1,
|
||||
special: false,
|
||||
minSpecial: 1
|
||||
};
|
||||
|
||||
// overload defaults with given options
|
||||
var o = angular.extend({}, defaults, options);
|
||||
|
||||
// sanitize
|
||||
if (o.uppercase && o.minUppercase < 0) o.minUppercase = 1;
|
||||
if (o.lowercase && o.minLowercase < 0) o.minLowercase = 1;
|
||||
if (o.number && o.minNumber < 0) o.minNumber = 1;
|
||||
if (o.special && o.minSpecial < 0) o.minSpecial = 1;
|
||||
|
||||
if (!o.length || o.length < 1) o.length = 10;
|
||||
var minLength = o.minUppercase + o.minLowercase + o.minNumber + o.minSpecial;
|
||||
if (o.length < minLength) o.length = minLength;
|
||||
|
||||
var positions = [];
|
||||
if (o.lowercase && o.minLowercase > 0) {
|
||||
for (var i = 0; i < o.minLowercase; i++) {
|
||||
positions.push('l');
|
||||
}
|
||||
}
|
||||
if (o.uppercase && o.minUppercase > 0) {
|
||||
for (var j = 0; j < o.minUppercase; j++) {
|
||||
positions.push('u');
|
||||
}
|
||||
}
|
||||
if (o.number && o.minNumber > 0) {
|
||||
for (var k = 0; k < o.minNumber; k++) {
|
||||
positions.push('n');
|
||||
}
|
||||
}
|
||||
if (o.special && o.minSpecial > 0) {
|
||||
for (var l = 0; l < o.minSpecial; l++) {
|
||||
positions.push('s');
|
||||
}
|
||||
}
|
||||
while (positions.length < o.length) {
|
||||
positions.push('a');
|
||||
}
|
||||
|
||||
// shuffle
|
||||
positions.sort(function () {
|
||||
return randomInt(0, 1) * 2 - 1;
|
||||
});
|
||||
|
||||
// build out the char sets
|
||||
var allCharSet = '';
|
||||
|
||||
var lowercaseCharSet = 'abcdefghijkmnopqrstuvwxyz';
|
||||
if (o.ambiguous) lowercaseCharSet += 'l';
|
||||
if (o.lowercase) allCharSet += lowercaseCharSet;
|
||||
|
||||
var uppercaseCharSet = 'ABCDEFGHIJKLMNPQRSTUVWXYZ';
|
||||
if (o.ambiguous) uppercaseCharSet += 'O';
|
||||
if (o.uppercase) allCharSet += uppercaseCharSet;
|
||||
|
||||
var numberCharSet = '23456789';
|
||||
if (o.ambiguous) numberCharSet += '01';
|
||||
if (o.number) allCharSet += numberCharSet;
|
||||
|
||||
var specialCharSet = '!@#$%^&*';
|
||||
if (o.special) allCharSet += specialCharSet;
|
||||
|
||||
var password = '';
|
||||
for (var m = 0; m < o.length; m++) {
|
||||
var positionChars;
|
||||
switch (positions[m]) {
|
||||
case 'l': positionChars = lowercaseCharSet; break;
|
||||
case 'u': positionChars = uppercaseCharSet; break;
|
||||
case 'n': positionChars = numberCharSet; break;
|
||||
case 's': positionChars = specialCharSet; break;
|
||||
case 'a': positionChars = allCharSet; break;
|
||||
}
|
||||
|
||||
var randomCharIndex = randomInt(0, positionChars.length - 1);
|
||||
password += positionChars.charAt(randomCharIndex);
|
||||
}
|
||||
|
||||
return password;
|
||||
};
|
||||
|
||||
// EFForg/OpenWireless
|
||||
// ref https://github.com/EFForg/OpenWireless/blob/master/app/js/diceware.js
|
||||
function randomInt(min, max) {
|
||||
var rval = 0;
|
||||
var range = max - min;
|
||||
|
||||
var bits_needed = Math.ceil(Math.log2(range));
|
||||
if (bits_needed > 53) {
|
||||
throw new Exception("We cannot generate numbers larger than 53 bits.");
|
||||
}
|
||||
var bytes_needed = Math.ceil(bits_needed / 8);
|
||||
var mask = Math.pow(2, bits_needed) - 1;
|
||||
// 7776 -> (2^13 = 8192) -1 == 8191 or 0x00001111 11111111
|
||||
|
||||
// Create byte array and fill with N random numbers
|
||||
var byteArray = new Uint8Array(bytes_needed);
|
||||
window.crypto.getRandomValues(byteArray);
|
||||
|
||||
var p = (bytes_needed - 1) * 8;
|
||||
for (var i = 0; i < bytes_needed; i++) {
|
||||
rval += byteArray[i] * Math.pow(2, p);
|
||||
p -= 8;
|
||||
}
|
||||
|
||||
// Use & to apply the mask and reduce the number of recursive lookups
|
||||
rval = rval & mask;
|
||||
|
||||
if (rval >= range) {
|
||||
// Integer out of acceptable range
|
||||
return randomInt(min, max);
|
||||
}
|
||||
// Return an integer that falls within the range
|
||||
return min + rval;
|
||||
}
|
||||
|
||||
return _service;
|
||||
});
|
||||
2
src/app/services/servicesModule.js
Normal file
2
src/app/services/servicesModule.js
Normal file
@@ -0,0 +1,2 @@
|
||||
angular
|
||||
.module('bit.services', ['ngResource', 'ngStorage', 'angular-jwt']);
|
||||
27
src/app/services/tokenService.js
Normal file
27
src/app/services/tokenService.js
Normal file
@@ -0,0 +1,27 @@
|
||||
angular
|
||||
.module('bit.services')
|
||||
|
||||
.factory('tokenService', function ($sessionStorage) {
|
||||
var _service = {},
|
||||
_token;
|
||||
|
||||
_service.setToken = function (token) {
|
||||
$sessionStorage.authBearer = token;
|
||||
_token = token;
|
||||
};
|
||||
|
||||
_service.getToken = function () {
|
||||
if (!_token) {
|
||||
_token = $sessionStorage.authBearer;
|
||||
}
|
||||
|
||||
return _token;
|
||||
};
|
||||
|
||||
_service.clearToken = function () {
|
||||
_token = null;
|
||||
delete $sessionStorage.authBearer;
|
||||
};
|
||||
|
||||
return _service;
|
||||
});
|
||||
62
src/app/services/validationService.js
Normal file
62
src/app/services/validationService.js
Normal file
@@ -0,0 +1,62 @@
|
||||
angular
|
||||
.module('bit.services')
|
||||
|
||||
.factory('validationService', function () {
|
||||
var _service = {};
|
||||
|
||||
_service.addErrors = function (form, reason) {
|
||||
var data = reason.data;
|
||||
var defaultErrorMessage = 'An unexpected error has occured.';
|
||||
form.$errors = [];
|
||||
|
||||
if (!data || !angular.isObject(data)) {
|
||||
form.$errors.push(defaultErrorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!data.ValidationErrors) {
|
||||
if (data.Message) {
|
||||
form.$errors.push(data.Message);
|
||||
}
|
||||
else {
|
||||
form.$errors.push(defaultErrorMessage);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (var key in data.ValidationErrors) {
|
||||
if (!data.ValidationErrors.hasOwnProperty(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (var i = 0; i < data.ValidationErrors[key].length; i++) {
|
||||
_service.addError(form, key, data.ValidationErrors[key][i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_service.addError = function (form, key, errorMessage, clearExistingErrors) {
|
||||
if (clearExistingErrors || !form.$errors) {
|
||||
form.$errors = [];
|
||||
}
|
||||
|
||||
var pushError = true;
|
||||
for (var i = 0; i < form.$errors.length; i++) {
|
||||
if (form.$errors[i] === errorMessage) {
|
||||
pushError = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pushError) {
|
||||
form.$errors.push(errorMessage);
|
||||
}
|
||||
|
||||
if (key && key !== '' && form[key] && form[key].$registerApiError) {
|
||||
form[key].$registerApiError();
|
||||
}
|
||||
};
|
||||
|
||||
return _service;
|
||||
});
|
||||
Reference in New Issue
Block a user