2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "PasswordManager.h"
11 #include "ServiceBroker.h"
13 #include "profiles/ProfileManager.h"
14 #include "profiles/dialogs/GUIDialogLockSettings.h"
15 #include "settings/SettingsComponent.h"
16 #include "utils/FileUtils.h"
17 #include "utils/StringUtils.h"
18 #include "utils/XMLUtils.h"
19 #include "utils/log.h"
23 CPasswordManager
&CPasswordManager::GetInstance()
25 static CPasswordManager sPasswordManager
;
26 return sPasswordManager
;
29 CPasswordManager::CPasswordManager()
34 bool CPasswordManager::AuthenticateURL(CURL
&url
)
36 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
40 std::string
lookup(GetLookupPath(url
));
41 std::map
<std::string
, std::string
>::const_iterator it
= m_temporaryCache
.find(lookup
);
42 if (it
== m_temporaryCache
.end())
43 { // second step, try something that doesn't quite match
44 it
= m_temporaryCache
.find(GetServerLookup(lookup
));
46 if (it
!= m_temporaryCache
.end())
48 CURL
auth(it
->second
);
49 url
.SetDomain(auth
.GetDomain());
50 url
.SetPassword(auth
.GetPassWord());
51 url
.SetUserName(auth
.GetUserName());
57 bool CPasswordManager::PromptToAuthenticateURL(CURL
&url
)
59 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
62 std::string username
= url
.GetUserName();
63 std::string domain
= url
.GetDomain();
65 username
= domain
+ '\\' + username
;
67 bool saveDetails
= false;
68 if (!CGUIDialogLockSettings::ShowAndGetUserAndPassword(username
, passcode
, url
.GetWithoutUserDetails(), &saveDetails
))
71 // domain/name to domain\name
72 std::string name
= username
;
73 std::replace(name
.begin(), name
.end(), '/', '\\');
75 if (url
.IsProtocol("smb") && name
.find('\\') != std::string::npos
)
77 auto pair
= StringUtils::Split(name
, '\\', 2);
78 url
.SetDomain(pair
[0]);
79 url
.SetUserName(pair
[1]);
84 url
.SetUserName(username
);
87 url
.SetPassword(passcode
);
89 // save the information for later
90 SaveAuthenticatedURL(url
, saveDetails
);
94 void CPasswordManager::SaveAuthenticatedURL(const CURL
&url
, bool saveToProfile
)
96 // don't store/save authenticated url if it doesn't contain username
97 if (url
.GetUserName().empty())
100 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
102 std::string path
= GetLookupPath(url
);
103 std::string authenticatedPath
= url
.Get();
109 { // write to some random XML file...
110 m_permanentCache
[path
] = authenticatedPath
;
114 // save for both this path and more generally the server as a whole.
115 m_temporaryCache
[path
] = authenticatedPath
;
116 m_temporaryCache
[GetServerLookup(path
)] = authenticatedPath
;
119 bool CPasswordManager::IsURLSupported(const CURL
&url
)
121 return url
.IsProtocol("smb")
122 || url
.IsProtocol("nfs")
123 || url
.IsProtocol("ftp")
124 || url
.IsProtocol("ftps")
125 || url
.IsProtocol("sftp")
126 || url
.IsProtocol("http")
127 || url
.IsProtocol("https")
128 || url
.IsProtocol("dav")
129 || url
.IsProtocol("davs");
132 void CPasswordManager::Clear()
134 m_temporaryCache
.clear();
135 m_permanentCache
.clear();
139 void CPasswordManager::Load()
143 const std::shared_ptr
<CProfileManager
> profileManager
= CServiceBroker::GetSettingsComponent()->GetProfileManager();
145 std::string passwordsFile
= profileManager
->GetUserDataItem("passwords.xml");
146 if (CFileUtils::Exists(passwordsFile
))
149 if (!doc
.LoadFile(passwordsFile
))
151 CLog::Log(LOGERROR
, "{} - Unable to load: {}, Line {}\n{}", __FUNCTION__
, passwordsFile
,
152 doc
.ErrorRow(), doc
.ErrorDesc());
155 const TiXmlElement
*root
= doc
.RootElement();
156 if (root
->ValueStr() != "passwords")
158 // read in our passwords
159 const TiXmlElement
*path
= root
->FirstChildElement("path");
162 std::string from
, to
;
163 if (XMLUtils::GetPath(path
, "from", from
) && XMLUtils::GetPath(path
, "to", to
))
165 m_permanentCache
[from
] = to
;
166 m_temporaryCache
[from
] = to
;
167 m_temporaryCache
[GetServerLookup(from
)] = to
;
169 path
= path
->NextSiblingElement("path");
175 void CPasswordManager::Save() const
177 if (m_permanentCache
.empty())
181 TiXmlElement
rootElement("passwords");
182 TiXmlNode
*root
= doc
.InsertEndChild(rootElement
);
186 for (std::map
<std::string
, std::string
>::const_iterator i
= m_permanentCache
.begin(); i
!= m_permanentCache
.end(); ++i
)
188 TiXmlElement
pathElement("path");
189 TiXmlNode
*path
= root
->InsertEndChild(pathElement
);
190 XMLUtils::SetPath(path
, "from", i
->first
);
191 XMLUtils::SetPath(path
, "to", i
->second
);
194 const std::shared_ptr
<CProfileManager
> profileManager
= CServiceBroker::GetSettingsComponent()->GetProfileManager();
196 doc
.SaveFile(profileManager
->GetUserDataItem("passwords.xml"));
199 std::string
CPasswordManager::GetLookupPath(const CURL
&url
) const
201 if (url
.IsProtocol("sftp"))
202 return GetServerLookup(url
.Get());
204 return url
.GetProtocol() + "://" + url
.GetHostName() + "/" + url
.GetShareName();
207 std::string
CPasswordManager::GetServerLookup(const std::string
&path
) const
210 return url
.GetProtocol() + "://" + url
.GetHostName() + "/";