mirror of
https://github.com/bitwarden/desktop.git
synced 2024-09-07 00:38:13 +02:00
more services and async callthroughs for vault list/add
This commit is contained in:
parent
32f4ab4987
commit
8f0a24b1b9
@ -3,3 +3,4 @@ var tokenService = new TokenService();
|
|||||||
var apiService = new ApiService(tokenService);
|
var apiService = new ApiService(tokenService);
|
||||||
var userService = new UserService(tokenService, apiService);
|
var userService = new UserService(tokenService, apiService);
|
||||||
var siteService = new SiteService(cryptoService, userService, apiService);
|
var siteService = new SiteService(cryptoService, userService, apiService);
|
||||||
|
var folderService = new FolderService(cryptoService, userService, apiService);
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
"services/tokenService.js",
|
"services/tokenService.js",
|
||||||
"services/apiService.js",
|
"services/apiService.js",
|
||||||
"services/userService.js",
|
"services/userService.js",
|
||||||
|
"services/folderService.js",
|
||||||
"services/siteService.js",
|
"services/siteService.js",
|
||||||
"background.js"
|
"background.js"
|
||||||
]
|
]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
var CipherString = function (encryptedString) {
|
var CipherString = function (encryptedString) {
|
||||||
this.encryptedString = encryptedString;
|
this.encryptedString = encryptedString;
|
||||||
|
|
||||||
if (encryptedString) {
|
if (encryptedString) {
|
||||||
@ -20,20 +20,35 @@
|
|||||||
};
|
};
|
||||||
}();
|
}();
|
||||||
|
|
||||||
var Site = function (obj) {
|
var Site = function (obj, alreadyEncrypted) {
|
||||||
var cryptoService = chrome.extension.getBackgroundPage().cryptoService;
|
|
||||||
|
|
||||||
this.id = obj.id;
|
this.id = obj.id;
|
||||||
this.folderId = obj.folderId;
|
this.folderId = obj.folderId;
|
||||||
this.name = cryptoService.encrypt(obj.name);
|
|
||||||
this.uri = cryptoService.encrypt(obj.uri);
|
if (alreadyEncrypted === true) {
|
||||||
this.username = cryptoService.encrypt(obj.username);
|
this.name = obj.name;
|
||||||
this.password = cryptoService.encrypt(obj.password);
|
this.uri = obj.uri;
|
||||||
this.notes = cryptoService.encrypt(obj.notes);
|
this.username = obj.username;
|
||||||
|
this.password = obj.password;
|
||||||
|
this.notes = obj.notes;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.name = new CipherString(obj.name);
|
||||||
|
this.uri = new CipherString(obj.uri);
|
||||||
|
this.username = new CipherString(obj.username);
|
||||||
|
this.password = new CipherString(obj.password);
|
||||||
|
this.notes = new CipherString(obj.notes);
|
||||||
|
}
|
||||||
|
|
||||||
this.favorite = new obj.favorite;
|
this.favorite = new obj.favorite;
|
||||||
};
|
};
|
||||||
|
|
||||||
var Folder = function (obj) {
|
var Folder = function (obj, alreadyEncrypted) {
|
||||||
this.id = obj.id;
|
this.id = obj.id;
|
||||||
|
|
||||||
|
if (alreadyEncrypted === true) {
|
||||||
|
this.name = obj.name;
|
||||||
|
}
|
||||||
|
else {
|
||||||
this.name = new CipherString(obj.name);
|
this.name = new CipherString(obj.name);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
@ -13,6 +13,9 @@
|
|||||||
.factory('apiService', function () {
|
.factory('apiService', function () {
|
||||||
return chrome.extension.getBackgroundPage().apiService;
|
return chrome.extension.getBackgroundPage().apiService;
|
||||||
})
|
})
|
||||||
|
.factory('folderService', function () {
|
||||||
|
return chrome.extension.getBackgroundPage().folderService;
|
||||||
|
})
|
||||||
.factory('siteService', function () {
|
.factory('siteService', function () {
|
||||||
return chrome.extension.getBackgroundPage().siteService;
|
return chrome.extension.getBackgroundPage().siteService;
|
||||||
});
|
});
|
||||||
|
@ -1,14 +1,41 @@
|
|||||||
angular
|
angular
|
||||||
.module('bit.vault')
|
.module('bit.vault')
|
||||||
|
|
||||||
.controller('vaultAddSiteController', function ($scope, siteService) {
|
.controller('vaultAddSiteController', function ($scope, siteService, cryptoService) {
|
||||||
$scope.site = {
|
$scope.site = {
|
||||||
folderId: null
|
folderId: null
|
||||||
};
|
};
|
||||||
$scope.createSite = function (model) {
|
|
||||||
var site = new Site(model);
|
|
||||||
siteService.save(model, function () {
|
|
||||||
|
|
||||||
|
$scope.createSite = function (model) {
|
||||||
|
var newModel = model;
|
||||||
|
encryptSite(newModel, function (siteModel) {
|
||||||
|
var site = new Site(siteModel, true);
|
||||||
|
siteService.save(site, function () {
|
||||||
|
$scope.close();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.close = function () {
|
||||||
|
$scope.parentScope.closeAddSite();
|
||||||
|
};
|
||||||
|
|
||||||
|
function encryptSite(siteModel, callback) {
|
||||||
|
cryptoService.encrypt(siteModel.name, function (nameCipherString) {
|
||||||
|
siteModel.name = nameCipherString;
|
||||||
|
cryptoService.encrypt(siteModel.uri, function (uriCipherString) {
|
||||||
|
siteModel.uri = uriCipherString;
|
||||||
|
cryptoService.encrypt(siteModel.username, function (usernameCipherString) {
|
||||||
|
siteModel.username = usernameCipherString;
|
||||||
|
cryptoService.encrypt(siteModel.password, function (passwordCipherString) {
|
||||||
|
siteModel.password = passwordCipherString;
|
||||||
|
cryptoService.encrypt(siteModel.notes, function (notesCipherString) {
|
||||||
|
siteModel.notes = notesCipherString;
|
||||||
|
callback(siteModel);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,41 @@
|
|||||||
angular
|
angular
|
||||||
.module('bit.vault')
|
.module('bit.vault')
|
||||||
|
|
||||||
.controller('vaultController', function ($scope, $ionicModal) {
|
.controller('vaultController', function ($scope, $ionicModal, siteService, folderService) {
|
||||||
|
$scope.parentScope = $scope;
|
||||||
|
$scope.sites = [];
|
||||||
|
$scope.folders = [];
|
||||||
|
|
||||||
|
var decSites = [];
|
||||||
|
var decFolders = [{
|
||||||
|
id: null,
|
||||||
|
name: '(none)'
|
||||||
|
}];
|
||||||
|
|
||||||
|
folderService.getAll(function (folders) {
|
||||||
|
siteService.getAll(function (sites) {
|
||||||
|
for (var i = 0; i < folders.length; i++) {
|
||||||
|
decFolders.push({
|
||||||
|
id: folders[i].id,
|
||||||
|
name: folders[i].name.decrypt()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var j = 0; j < sites.length; j++) {
|
||||||
|
decSites.push({
|
||||||
|
id: sites[j].id,
|
||||||
|
folderId: sites[j].folderId,
|
||||||
|
favorite: sites[j].favorite,
|
||||||
|
name: sites[j].name.decrypt(),
|
||||||
|
username: sites[j].username.decrypt()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.sites = decSites;
|
||||||
|
$scope.folders = decFolders;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
$scope.addSite = function () {
|
$scope.addSite = function () {
|
||||||
$ionicModal.fromTemplateUrl('app/vault/views/vaultAddSite.html', {
|
$ionicModal.fromTemplateUrl('app/vault/views/vaultAddSite.html', {
|
||||||
scope: $scope,
|
scope: $scope,
|
||||||
|
@ -2,9 +2,12 @@
|
|||||||
<ion-nav-buttons side="secondary">
|
<ion-nav-buttons side="secondary">
|
||||||
<button class="button button-icon icon ion-ios-plus-empty" ng-click="addSite()"></button>
|
<button class="button button-icon icon ion-ios-plus-empty" ng-click="addSite()"></button>
|
||||||
</ion-nav-buttons>
|
</ion-nav-buttons>
|
||||||
<ion-content class="padding">
|
<ion-content>
|
||||||
<p>
|
<div class="list">
|
||||||
Some content for your vault.
|
<div class="item item-button-right">
|
||||||
</p>
|
Site 1
|
||||||
|
<button class="button button-clear button-dark"><i class="icon ion-more"></i></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
</ion-view>
|
</ion-view>
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<ion-modal-view>
|
<ion-modal-view ng-controller="vaultAddSiteController">
|
||||||
<ion-header-bar class="bar bar-header bar-positive">
|
<ion-header-bar class="bar bar-header bar-positive">
|
||||||
<button class="button button-clear button-primary" ng-click="addSiteModal.hide()">Cancel</button>
|
<button class="button button-clear button-primary" ng-click="close()">Cancel</button>
|
||||||
<h1 class="title">Add Site</h1>
|
<h1 class="title">Add Site</h1>
|
||||||
<button class="button button-clear button-primary" ng-click="createSite(site)">Save</button>
|
<button class="button button-clear button-primary" ng-click="createSite(site)">Save</button>
|
||||||
</ion-header-bar>
|
</ion-header-bar>
|
||||||
<ion-content ng-controller="vaultAddSiteController">
|
<ion-content>
|
||||||
<div class="list">
|
<div class="list">
|
||||||
<div class="item item-divider">
|
<div class="item item-divider">
|
||||||
Site Information
|
Site Information
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
function ApiService(tokenService) {
|
function ApiService(tokenService) {
|
||||||
this.baseUrl = 'https://api.bitwarden.com';
|
this.baseUrl = 'https://api.bitwarden.com';
|
||||||
this.tokenService = tokenService;
|
this.tokenService = tokenService;
|
||||||
|
|
||||||
|
initApiService();
|
||||||
};
|
};
|
||||||
|
|
||||||
!function () {
|
function initApiService() {
|
||||||
// Auth APIs
|
// Auth APIs
|
||||||
|
|
||||||
ApiService.prototype.postToken = function (tokenRequest, success, error) {
|
ApiService.prototype.postToken = function (tokenRequest, success, error) {
|
||||||
@ -235,4 +237,4 @@
|
|||||||
function handleError(errorCallback, jqXHR, textStatus, errorThrown) {
|
function handleError(errorCallback, jqXHR, textStatus, errorThrown) {
|
||||||
errorCallback(new ErrorResponse(jqXHR));
|
errorCallback(new ErrorResponse(jqXHR));
|
||||||
}
|
}
|
||||||
}();
|
};
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
function CryptoService() {
|
function CryptoService() {
|
||||||
|
initCryptoService();
|
||||||
};
|
};
|
||||||
|
|
||||||
!function () {
|
function initCryptoService() {
|
||||||
var _key,
|
var _key,
|
||||||
_b64Key,
|
_b64Key,
|
||||||
_aes;
|
_aes;
|
||||||
@ -32,9 +32,9 @@
|
|||||||
return callback(_key);
|
return callback(_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
chrome.storage.local.get('key', function (key) {
|
chrome.storage.local.get('key', function (obj) {
|
||||||
if (key) {
|
if (obj && obj.key) {
|
||||||
_key = sjcl.codec.base64.toBits(key);
|
_key = sjcl.codec.base64.toBits(obj.key);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (b64 && b64 === true) {
|
if (b64 && b64 === true) {
|
||||||
@ -80,21 +80,28 @@
|
|||||||
return sjcl.codec.base64.fromBits(hashBits);
|
return sjcl.codec.base64.fromBits(hashBits);
|
||||||
};
|
};
|
||||||
|
|
||||||
CryptoService.prototype.getAes = function () {
|
CryptoService.prototype.getAes = function (callback) {
|
||||||
if (!_aes && this.getKey()) {
|
if (!callback || typeof callback !== 'function') {
|
||||||
_aes = new sjcl.cipher.aes(this.getKey());
|
throw 'callback function required';
|
||||||
}
|
}
|
||||||
|
|
||||||
return _aes;
|
this.getKey(false, function (key) {
|
||||||
|
if (!_aes && key) {
|
||||||
|
_aes = new sjcl.cipher.aes(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(_aes);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
CryptoService.prototype.encrypt = function (plaintextValue, key) {
|
CryptoService.prototype.encrypt = function (plaintextValue, callback) {
|
||||||
if (!this.getKey() && !key) {
|
if (!callback || typeof callback !== 'function') {
|
||||||
throw 'Encryption key unavailable.';
|
throw 'callback function required';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.getKey(false, function (key) {
|
||||||
if (!key) {
|
if (!key) {
|
||||||
key = this.getKey();
|
throw 'Encryption key unavailable.';
|
||||||
}
|
}
|
||||||
|
|
||||||
var response = {};
|
var response = {};
|
||||||
@ -108,18 +115,25 @@
|
|||||||
var ct = ctJson.match(/"ct":"([^"]*)"/)[1];
|
var ct = ctJson.match(/"ct":"([^"]*)"/)[1];
|
||||||
var iv = sjcl.codec.base64.fromBits(response.iv);
|
var iv = sjcl.codec.base64.fromBits(response.iv);
|
||||||
|
|
||||||
return new CipherString(iv + "|" + ct);
|
callback(new CipherString(iv + "|" + ct));
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
CryptoService.prototype.decrypt = function (cipherString) {
|
CryptoService.prototype.decrypt = function (cipherStrin, callback) {
|
||||||
if (!this.getAes()) {
|
if (!callback || typeof callback !== 'function') {
|
||||||
|
throw 'callback function required';
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getAes(function (aes) {
|
||||||
|
if (!aes) {
|
||||||
throw 'AES encryption unavailable.';
|
throw 'AES encryption unavailable.';
|
||||||
}
|
}
|
||||||
|
|
||||||
var ivBits = sjcl.codec.base64.toBits(cipherString.initializationVector);
|
var ivBits = sjcl.codec.base64.toBits(cipherString.initializationVector);
|
||||||
var ctBits = sjcl.codec.base64.toBits(cipherString.cipherText);
|
var ctBits = sjcl.codec.base64.toBits(cipherString.cipherText);
|
||||||
|
|
||||||
var decBits = sjcl.mode.cbc.decrypt(this.getAes(), ctBits, ivBits, null);
|
var decBits = sjcl.mode.cbc.decrypt(aes, ctBits, ivBits, null);
|
||||||
return sjcl.codec.utf8String.fromBits(decBits);
|
callback(sjcl.codec.utf8String.fromBits(decBits));
|
||||||
|
});
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}();
|
|
||||||
|
50
src/services/folderService.js
Normal file
50
src/services/folderService.js
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
function FolderService(cryptoService, userService, apiService) {
|
||||||
|
this.cryptoService = cryptoService;
|
||||||
|
this.userService = userService;
|
||||||
|
this.apiService = apiService;
|
||||||
|
|
||||||
|
initFolderService();
|
||||||
|
};
|
||||||
|
|
||||||
|
function initFolderService() {
|
||||||
|
this.userService.getUserId(function (userId) {
|
||||||
|
var foldersKey = 'folders_' + userId;
|
||||||
|
|
||||||
|
FolderService.prototype.get = function (id, callback) {
|
||||||
|
if (!callback || typeof callback !== 'function') {
|
||||||
|
throw 'callback function required';
|
||||||
|
}
|
||||||
|
|
||||||
|
chrome.storage.local.get(foldersKey, function (obj) {
|
||||||
|
var folders = obj[foldersKey];
|
||||||
|
if (id in folders) {
|
||||||
|
callback(new Folder(folders[id]));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(null);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
FolderService.prototype.getAll = function (callback) {
|
||||||
|
if (!callback || typeof callback !== 'function') {
|
||||||
|
throw 'callback function required';
|
||||||
|
}
|
||||||
|
|
||||||
|
chrome.storage.local.get(foldersKey, function (obj) {
|
||||||
|
var folders = obj[foldersKey];
|
||||||
|
var response = [];
|
||||||
|
for (var id in folders) {
|
||||||
|
var folder = folders[id];
|
||||||
|
response.push(new Folder(folder));
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(response);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleError() {
|
||||||
|
// TODO: check for unauth or forbidden and logout
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
@ -2,22 +2,21 @@
|
|||||||
this.cryptoService = cryptoService;
|
this.cryptoService = cryptoService;
|
||||||
this.userService = userService;
|
this.userService = userService;
|
||||||
this.apiService = apiService;
|
this.apiService = apiService;
|
||||||
|
|
||||||
|
initSiteService();
|
||||||
};
|
};
|
||||||
|
|
||||||
!function () {
|
function initSiteService() {
|
||||||
var ciphersKey = 'ciphers_' + this.userService.userId;
|
this.userService.getUserId(function (userId) {
|
||||||
|
var sitesKey = 'sites_' + userId;
|
||||||
|
|
||||||
SiteService.prototype.get = function (id, callback) {
|
SiteService.prototype.get = function (id, callback) {
|
||||||
if (!callback || typeof callback !== 'function') {
|
if (!callback || typeof callback !== 'function') {
|
||||||
throw 'callback function required';
|
throw 'callback function required';
|
||||||
}
|
}
|
||||||
|
|
||||||
chrome.storage.local.get(ciphersKey, function (obj) {
|
chrome.storage.local.get(sitesKey, function (obj) {
|
||||||
if (!obj) {
|
var sites = obj[sitesKey];
|
||||||
callback(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
var sites = obj[ciphersKey];
|
|
||||||
if (id in sites) {
|
if (id in sites) {
|
||||||
callback(new Site(sites[id]));
|
callback(new Site(sites[id]));
|
||||||
return;
|
return;
|
||||||
@ -32,12 +31,8 @@
|
|||||||
throw 'callback function required';
|
throw 'callback function required';
|
||||||
}
|
}
|
||||||
|
|
||||||
chrome.storage.local.get(ciphersKey, function (obj) {
|
chrome.storage.local.get(sitesKey, function (obj) {
|
||||||
if (!obj) {
|
var sites = obj[sitesKey];
|
||||||
callback([]);
|
|
||||||
}
|
|
||||||
|
|
||||||
var sites = obj[ciphersKey];
|
|
||||||
var response = [];
|
var response = [];
|
||||||
for (var id in sites) {
|
for (var id in sites) {
|
||||||
response.push(new Site(sites[id]));
|
response.push(new Site(sites[id]));
|
||||||
@ -67,13 +62,8 @@
|
|||||||
userService.getUserId(function (userId) {
|
userService.getUserId(function (userId) {
|
||||||
var data = new SiteData(response, userId);
|
var data = new SiteData(response, userId);
|
||||||
|
|
||||||
chrome.storage.local.get(ciphersKey, function (obj) {
|
chrome.storage.local.get(sitesKey, function (obj) {
|
||||||
if (!obj) {
|
var sites = obj[sitesKey];
|
||||||
obj = {};
|
|
||||||
obj[ciphersKey] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
var sites = obj[ciphersKey];
|
|
||||||
if (!newRecord && site.id in sites) {
|
if (!newRecord && site.id in sites) {
|
||||||
sites[site.id] = data;
|
sites[site.id] = data;
|
||||||
}
|
}
|
||||||
@ -82,7 +72,7 @@
|
|||||||
site.id = data.id;
|
site.id = data.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
obj[ciphersKey] = sites;
|
obj[sitesKey] = sites;
|
||||||
chrome.storage.local.set(obj, function () {
|
chrome.storage.local.set(obj, function () {
|
||||||
callback(site);
|
callback(site);
|
||||||
});
|
});
|
||||||
@ -100,18 +90,13 @@
|
|||||||
|
|
||||||
function apiSuccess(response) {
|
function apiSuccess(response) {
|
||||||
userService.getUserId(function (userId) {
|
userService.getUserId(function (userId) {
|
||||||
chrome.storage.local.get(ciphersKey, function (obj) {
|
chrome.storage.local.get(sitesKey, function (obj) {
|
||||||
if (!obj) {
|
var sites = obj[sitesKey];
|
||||||
obj = {};
|
|
||||||
obj[ciphersKey] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
var sites = obj[ciphersKey];
|
|
||||||
if (id in sites) {
|
if (id in sites) {
|
||||||
var index = sites.indexOf(sites[id]);
|
var index = sites.indexOf(sites[id]);
|
||||||
sites.splice(index, 1);
|
sites.splice(index, 1);
|
||||||
|
|
||||||
obj[ciphersKey] = sites;
|
obj[sitesKey] = sites;
|
||||||
chrome.storage.local.set(obj, function () {
|
chrome.storage.local.set(obj, function () {
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
@ -124,8 +109,8 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
function handleError() {
|
function handleError() {
|
||||||
// TODO: check for unauth or forbidden and logout
|
// TODO: check for unauth or forbidden and logout
|
||||||
}
|
}
|
||||||
}();
|
});
|
||||||
|
};
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
function TokenService() {
|
function TokenService() {
|
||||||
|
initTokenService();
|
||||||
};
|
};
|
||||||
|
|
||||||
!function () {
|
function initTokenService() {
|
||||||
var _token;
|
var _token;
|
||||||
|
|
||||||
TokenService.prototype.setToken = function (token, callback) {
|
TokenService.prototype.setToken = function (token, callback) {
|
||||||
@ -101,4 +101,4 @@
|
|||||||
}
|
}
|
||||||
return window.decodeURIComponent(escape(window.atob(output))); //polyfill https://github.com/davidchambers/Base64.js
|
return window.decodeURIComponent(escape(window.atob(output))); //polyfill https://github.com/davidchambers/Base64.js
|
||||||
};
|
};
|
||||||
}();
|
};
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
function UserService(tokenService, apiService) {
|
function UserService(tokenService, apiService) {
|
||||||
this.tokenService = tokenService;
|
this.tokenService = tokenService;
|
||||||
this.apiService = apiService;
|
this.apiService = apiService;
|
||||||
|
|
||||||
|
initUserService();
|
||||||
};
|
};
|
||||||
|
|
||||||
!function () {
|
function initUserService() {
|
||||||
var _userProfile = null;
|
var _userProfile = null;
|
||||||
|
|
||||||
UserService.prototype.getUserId = function (callback) {
|
UserService.prototype.getUserId = function (callback) {
|
||||||
@ -90,4 +92,4 @@
|
|||||||
callback(profile !== null && profile.twoFactor);
|
callback(profile !== null && profile.twoFactor);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}();
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user