"use strict";
const EXPORTED_SYMBOLS = ["pwdmng"];
const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const pwdmng = {
AUTH_PASSPORT_URL: "https://passport.yandex.ru",
classDescription: "Password Manager and Passwords Auto-Complete Search",
contractID: "@mozilla.org/autocomplete/search;1?name=YaPassComplete",
classID: Components.ID("{7a19ec9e-54e4-4099-ae92-ac3628c67889}"),
_xpcom_categories: [{
category: "app-startup",
service: true}],
init: function pwdmng_init(api) {
if (this._initialized)
return;
this._initialized = true;
this._api = api;
Cu.import(this._api.Package.resolvePath("/native/fx/modules/yauth.jsm"),this);
try {
this._migrateFromOldVersions();
this.resetSavedLogins();
}
catch (e) {

}

}
,
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, Ci.nsIAutoCompleteSearch]),
createInstance: function pwdmng_createInstance(aOuter, aIID) this.QueryInterface(aIID),
controller: Cc["@mozilla.org/autocomplete/controller;1"].getService(Ci.nsIAutoCompleteController),
startSearch: function pwdmng_startSearch(searchString, searchParam, previousResult, listener) {
var candidats = [];
try {
candidats = searchString ? this.savedLogins.filter(function (login) login.indexOf(searchString) === 0) : this.savedLogins;
}
catch (e) {
return;
}

var that = this;
var control = this.controller.input;
var result = {
QueryInterface: function (aIID) {
if (aIID.equals(Ci.nsIAutoCompleteSearch) || aIID.equals(Ci.nsISupports))
return this;
throw Components.results.NS_NOINTERFACE;
}
,
results: candidats,
defaultIndex: 0,
errorDescription: null,
matchCount: candidats.length,
searchResult: Ci.nsIAutoCompleteResult[candidats.length ? "RESULT_SUCCESS" : "RESULT_NOMATCH"],
searchString: searchString,
getCommentAt: function (index) "",
getStyleAt: function (index) {
var defaultMaxRows = control.popup.popupOpen ? control.popup.maxRows : control.popup.defaultMaxRows;
var prefix = this.matchCount <= (searchString ? defaultMaxRows : control.popup.maxRows) ? "noscroll" : "scroll";
return that.onHoverTreeUglyHack ? "columnHover" + prefix : prefix;
}
,
getImageAt: function (index) "",
getValueAt: function (index) this.results[index],
getLabelAt: function (index) this.getValueAt(index),
removeValueAt: function (rowIndex, removeFromDb) {

}
};
listener.onSearchResult(this,result);
}
,
stopSearch: function pwdmng_stopSearch() {

}
,
get loginManager() {
return Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
}
,
_defaultUserPrefName: "users.default",
get onHoverTreeUglyHack() {
return this.__onHoverTreeUglyHack;
}
,
set onHoverTreeUglyHack(val) {
this.__onHoverTreeUglyHack = ! ! val;
return this.__onHoverTreeUglyHack;
}
,
_getLoginURL: function pwdmng__getLoginURL(strType) {
if (strType == this.authdefs.USER_TYPES.USER_MFD)
return this.AUTH_PASSPORT_URL + "/" + strType;
return this.AUTH_PASSPORT_URL;
}
,
_savedLogins: null,
get defaultUsername() {
return this.getPref(this._defaultUserPrefName);
}
,
resetSavedLogins: function pwdmng_resetSavedLogins() {
this.savedLogins = null;
}
,
set savedLogins(val) {
if (val !== null)
throw new Error("PassManager.savedLogins must be null");
this._savedLogins = null;
}
,
get savedLogins() {
return this._savedLogins || (this._savedLogins = this.getSavedLogins());
}
,
getSavedLogins: function pwdmng_getSavedLogins(arrTypes) {
var logins = [];
var types = arrTypes || [this.authdefs.USER_TYPES.USER_MFD, this.authdefs.USER_TYPES.USER_YANDEX];
types.forEach(function (strType) {
var passportURL = this._getLoginURL(strType);
logins = logins.concat(this.loginManager.findLogins({
},passportURL,passportURL,null).map(function (login) login.username));
}
,this);
return logins.sort();
}
,
get hasSavedLogins() {
return ! ! this.savedLogins.length;
}
,
_prepareUsername: function pwdmng__prepareUsername(strUsername, strType) {
if (strType == this.authdefs.USER_TYPES.USER_MFD)
return strUsername;
function toLowerWithoutDots(str) str.toLowerCase().replace(/\./g,"-")
var usernameLower = toLowerWithoutDots(strUsername);
var savedLogins = this.savedLogins;
return savedLogins.filter(function (strLogin) {
return strLogin === strUsername || toLowerWithoutDots(strLogin) === usernameLower || strLogin.split("@")[0] === strUsername || toLowerWithoutDots(strLogin).split("@")[0] === usernameLower;
}
)[0] || strUsername;
}
,
_loginManagerFindLogin: function pwdmng__loginManagerFindLogin(strUsername, strType) {
var types = strType ? [strType] : [this.authdefs.USER_TYPES.USER_MFD, this.authdefs.USER_TYPES.USER_YANDEX];
for(let [index, type] in Iterator(types)) {
let passportURL = this._getLoginURL(type);
let storedLogins = this.loginManager.findLogins({
},passportURL,passportURL,null);
for (let i = 0, len = storedLogins.length;i < len;i++) {
let username = storedLogins[i].username;
if (username == strUsername || type == this.authdefs.USER_TYPES.USER_YANDEX && username.split("@")[0] == strUsername)
{
return storedLogins[i];
}

}

}

return null;
}
,
_removeUserData: function pwdmng__removeUserData(strUsername, strType) {
var login = this._loginManagerFindLogin(strUsername,strType);
if (! login)
return false;
this.loginManager.removeLogin(login);
return true;
}
,
notifyObservers: function pwdmng_notifyObservers() {
Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService).notifyObservers(null,"refresh-data","login");
}
,
forgetAllUsers: function pwdmng_forgetAllUsers() {
this.resetSavedLogins();
var loginManager = this.loginManager;
var loginsToForget = [];
[this.authdefs.USER_TYPES.USER_MFD, this.authdefs.USER_TYPES.USER_YANDEX].forEach(function (type) {
var passportURL = this._getLoginURL(type);
loginsToForget = loginsToForget.concat(loginManager.findLogins({
},passportURL,passportURL,null));
}
,this);
loginsToForget.forEach(function (login) loginManager.removeLogin(login));
this.notifyObservers();
this.setPref(this._defaultUserPrefName,"");
}
,
removeUserData: function pwdmng_removeUserData(strUsername, strType) {
var username = this._prepareUsername(strUsername,strType);
this.resetSavedLogins();
if (this._removeUserData(username,strType))
{
this.notifyObservers();
}

if (strType == this.authdefs.USER_TYPES.USER_YANDEX)
{
if (username == this.getPref(this._defaultUserPrefName))
{
this.setPref(this._defaultUserPrefName,"");
}

}

}
,
getStoredPassword: function pwdmng_getStoredPassword(strUsername) {
var login = this._loginManagerFindLogin(this._prepareUsername(strUsername,this.authdefs.USER_TYPES.USER_MFD),this.authdefs.USER_TYPES.USER_MFD) || this._loginManagerFindLogin(this._prepareUsername(strUsername,this.authdefs.USER_TYPES.USER_YANDEX),this.authdefs.USER_TYPES.USER_YANDEX);
return login ? login.password : null;
}
,
getSavedLoginInfo: function pwdmng_getSavedLoginInfo(strUsername) {
var result = {
password: null,
type: this.authdefs.USER_TYPES.USER_YANDEX};
var userLogin = this._loginManagerFindLogin(this._prepareUsername(strUsername,this.authdefs.USER_TYPES.USER_MFD),this.authdefs.USER_TYPES.USER_MFD);
if (userLogin)
{
result.type = this.authdefs.USER_TYPES.USER_MFD;
}
 else
{
userLogin = this._loginManagerFindLogin(this._prepareUsername(strUsername,this.authdefs.USER_TYPES.USER_YANDEX),this.authdefs.USER_TYPES.USER_YANDEX);
}

if (! userLogin)
return null;
result.password = userLogin.password;
return result;
}
,
getSavedLoginsInfo: function pwdmng_getSavedLoginsInfo(arrTypes) {
var logins = [];
var types = arrTypes || [this.authdefs.USER_TYPES.USER_MFD, this.authdefs.USER_TYPES.USER_YANDEX];
types.forEach(function (strType) {
var passportURL = this._getLoginURL(strType);
var storedLogins = this.loginManager.findLogins({
},passportURL,passportURL,null);
for (let i = 0, len = storedLogins.length;i < len;i++) {
let login = storedLogins[i];
logins.push({
username: login.username,
password: login.password,
type: strType});
}

}
,this);
return logins;
}
,
removeAllUsersData: function pwdmng_removeAllUsersData() {
this.savedLogins.forEach(function (aUsername) {
this._removeUserData(aUsername);
}
,this);
this.setPref(this._defaultUserPrefName);
this.resetSavedLogins();
}
,
storeLoginDetails: function pwdmng_storeLoginDetails(strUsername, strPassword, bToStore, strType) {
if (strType == this.authdefs.USER_TYPES.USER_MFD)
{
strUsername = strUsername.toLowerCase();
}

this.removeUserData(strUsername,strType);
if (bToStore)
{
const nsLoginInfo = new Components.Constructor("@mozilla.org/login-manager/loginInfo;1", Ci.nsILoginInfo, "init");
let chromeURL = this._getLoginURL(strType);
let loginInfo = new nsLoginInfo(chromeURL, chromeURL, null, strUsername, strPassword, "", "");
this.loginManager.addLogin(loginInfo);
if (strType == this.authdefs.USER_TYPES.USER_YANDEX)
{
this.setPref(this._defaultUserPrefName,strUsername);
}

this.resetSavedLogins();
this.notifyObservers();
}

}
,
_migrateFromOldVersions: function pwdmng__migrateFromOldVersions() {
var authTypes = this.authdefs.USER_TYPES;
var getLoginChromeURL = function getLoginChromeURL(type) {
return type == authTypes.USER_MFD ? "chrome://yasearch/mfd/" : "chrome://yasearch/";
}
;
[authTypes.USER_MFD, authTypes.USER_YANDEX].forEach(function (type) {
var chromeURL = getLoginChromeURL(type);
var logins = this.loginManager.findLogins({
},chromeURL,chromeURL,null);
logins.forEach(function (login) {
if (this.getSavedLoginInfo(login.username))
return;
this.storeLoginDetails(login.username,login.password,true,type);
this.loginManager.removeLogin(login);
}
,this);
}
,this);
}
,
setPref: function pwdmng_setPref(strPrefName, strPrefValue) {
var prefFullName = this._api.Settings.getPackageBranchPath() + strPrefName;
return this._api.Settings.PrefsModule.set(prefFullName,strPrefValue);
}
,
getPref: function pwdmng_getPref(strPrefName, defaultValue) {
var prefFullName = this._api.Settings.getPackageBranchPath() + strPrefName;
return this._api.Settings.PrefsModule.get(prefFullName,defaultValue);
}
};
