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/XBMCTinyXML2.h"
19 #include "utils/XMLUtils.h"
20 #include "utils/log.h"
25 CPasswordManager
&CPasswordManager::GetInstance()
27 static CPasswordManager sPasswordManager
;
28 return sPasswordManager
;
31 CPasswordManager::CPasswordManager()
36 bool CPasswordManager::AuthenticateURL(CURL
&url
)
38 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
42 std::string
lookup(GetLookupPath(url
));
43 std::map
<std::string
, std::string
>::const_iterator it
= m_temporaryCache
.find(lookup
);
44 if (it
== m_temporaryCache
.end())
45 { // second step, try something that doesn't quite match
46 it
= m_temporaryCache
.find(GetServerLookup(lookup
));
48 if (it
!= m_temporaryCache
.end())
50 CURL
auth(it
->second
);
51 url
.SetDomain(auth
.GetDomain());
52 url
.SetPassword(auth
.GetPassWord());
53 url
.SetUserName(auth
.GetUserName());
59 bool CPasswordManager::PromptToAuthenticateURL(CURL
&url
)
61 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
64 std::string username
= url
.GetUserName();
65 std::string domain
= url
.GetDomain();
67 username
= domain
+ '\\' + username
;
69 bool saveDetails
= false;
70 if (!CGUIDialogLockSettings::ShowAndGetUserAndPassword(username
, passcode
, url
.GetWithoutUserDetails(), &saveDetails
))
73 // domain/name to domain\name
74 std::string name
= username
;
75 std::replace(name
.begin(), name
.end(), '/', '\\');
77 if (url
.IsProtocol("smb") && name
.find('\\') != std::string::npos
)
79 auto pair
= StringUtils::Split(name
, '\\', 2);
80 url
.SetDomain(pair
[0]);
81 url
.SetUserName(pair
[1]);
86 url
.SetUserName(username
);
89 url
.SetPassword(passcode
);
91 // save the information for later
92 SaveAuthenticatedURL(url
, saveDetails
);
96 void CPasswordManager::SaveAuthenticatedURL(const CURL
&url
, bool saveToProfile
)
98 // don't store/save authenticated url if it doesn't contain username
99 if (url
.GetUserName().empty())
102 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
104 std::string path
= GetLookupPath(url
);
105 std::string authenticatedPath
= url
.Get();
111 { // write to some random XML file...
112 m_permanentCache
[path
] = authenticatedPath
;
116 // save for both this path and more generally the server as a whole.
117 m_temporaryCache
[path
] = authenticatedPath
;
118 m_temporaryCache
[GetServerLookup(path
)] = authenticatedPath
;
121 bool CPasswordManager::IsURLSupported(const CURL
&url
)
123 return url
.IsProtocol("smb")
124 || url
.IsProtocol("nfs")
125 || url
.IsProtocol("ftp")
126 || url
.IsProtocol("ftps")
127 || url
.IsProtocol("sftp")
128 || url
.IsProtocol("http")
129 || url
.IsProtocol("https")
130 || url
.IsProtocol("dav")
131 || url
.IsProtocol("davs");
134 void CPasswordManager::Clear()
136 m_temporaryCache
.clear();
137 m_permanentCache
.clear();
141 void CPasswordManager::Load()
145 const std::shared_ptr
<CProfileManager
> profileManager
= CServiceBroker::GetSettingsComponent()->GetProfileManager();
147 std::string passwordsFile
= profileManager
->GetUserDataItem("passwords.xml");
148 if (CFileUtils::Exists(passwordsFile
))
151 if (!doc
.LoadFile(passwordsFile
))
153 CLog::LogF(LOGERROR
, "Unable to load: {}, Line {}\n{}", passwordsFile
, doc
.ErrorLineNum(),
157 const auto* root
= doc
.RootElement();
161 if (std::strcmp(root
->Value(), "passwords") != 0)
163 // read in our passwords
164 const auto* path
= root
->FirstChildElement("path");
165 while (path
!= nullptr)
167 std::string from
, to
;
168 if (XMLUtils::GetPath(path
, "from", from
) && XMLUtils::GetPath(path
, "to", to
))
170 m_permanentCache
[from
] = to
;
171 m_temporaryCache
[from
] = to
;
172 m_temporaryCache
[GetServerLookup(from
)] = to
;
174 path
= path
->NextSiblingElement("path");
180 void CPasswordManager::Save() const
182 if (m_permanentCache
.empty())
186 auto* rootElement
= doc
.NewElement("passwords");
187 if (rootElement
== nullptr)
190 auto* root
= doc
.InsertEndChild(rootElement
);
194 for (std::map
<std::string
, std::string
>::const_iterator i
= m_permanentCache
.begin(); i
!= m_permanentCache
.end(); ++i
)
196 auto* pathElement
= doc
.NewElement("path");
197 if (pathElement
== nullptr)
200 auto* path
= root
->InsertEndChild(pathElement
);
204 XMLUtils::SetPath(path
, "from", i
->first
);
205 XMLUtils::SetPath(path
, "to", i
->second
);
208 const std::shared_ptr
<CProfileManager
> profileManager
= CServiceBroker::GetSettingsComponent()->GetProfileManager();
210 doc
.SaveFile(profileManager
->GetUserDataItem("passwords.xml"));
213 std::string
CPasswordManager::GetLookupPath(const CURL
&url
) const
215 if (url
.IsProtocol("sftp"))
216 return GetServerLookup(url
.Get());
218 return url
.GetProtocol() + "://" + url
.GetHostName() + "/" + url
.GetShareName();
221 std::string
CPasswordManager::GetServerLookup(const std::string
&path
) const
224 return url
.GetProtocol() + "://" + url
.GetHostName() + "/";