1/*
2 * Copyright (C) 2010 Stephan A��mus <superstippi@gmx.de>
3 *
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "CredentialsStorage.h"
29
30#include <new>
31#include <stdio.h>
32
33#include <Autolock.h>
34#include <Entry.h>
35#include <File.h>
36#include <FindDirectory.h>
37#include <Message.h>
38#include <Path.h>
39
40#include "BrowserApp.h"
41
42
43Credentials::Credentials()
44	:
45	fUsername(),
46	fPassword()
47{
48}
49
50
51Credentials::Credentials(const BString& username, const BString& password)
52	:
53	fUsername(username),
54	fPassword(password)
55{
56}
57
58
59Credentials::Credentials(const Credentials& other)
60{
61	*this = other;
62}
63
64
65Credentials::Credentials(const BMessage* archive)
66{
67	if (archive == NULL)
68		return;
69	archive->FindString("username", &fUsername);
70	archive->FindString("password", &fPassword);
71}
72
73
74Credentials::~Credentials()
75{
76}
77
78
79status_t
80Credentials::Archive(BMessage* archive) const
81{
82	if (archive == NULL)
83		return B_BAD_VALUE;
84	status_t status = archive->AddString("username", fUsername);
85	if (status == B_OK)
86		status = archive->AddString("password", fPassword);
87	return status;
88}
89
90
91Credentials&
92Credentials::operator=(const Credentials& other)
93{
94	if (this == &other)
95		return *this;
96
97	fUsername = other.fUsername;
98	fPassword = other.fPassword;
99
100	return *this;
101}
102
103
104bool
105Credentials::operator==(const Credentials& other) const
106{
107	if (this == &other)
108		return true;
109
110	return fUsername == other.fUsername && fPassword == other.fPassword;
111}
112
113
114bool
115Credentials::operator!=(const Credentials& other) const
116{
117	return !(*this == other);
118}
119
120
121const BString&
122Credentials::Username() const
123{
124	return fUsername;
125}
126
127
128const BString&
129Credentials::Password() const
130{
131	return fPassword;
132}
133
134
135// #pragma mark - CredentialsStorage
136
137
138CredentialsStorage
139CredentialsStorage::sPersistentInstance(true);
140
141
142CredentialsStorage
143CredentialsStorage::sSessionInstance(false);
144
145
146CredentialsStorage::CredentialsStorage(bool persistent)
147	:
148	BLocker(persistent ? "persistent credential storage"
149		: "credential storage"),
150	fCredentialMap(),
151	fSettingsLoaded(false),
152	fPersistent(persistent)
153{
154}
155
156
157CredentialsStorage::~CredentialsStorage()
158{
159	_SaveSettings();
160}
161
162
163/*static*/ CredentialsStorage*
164CredentialsStorage::SessionInstance()
165{
166	return &sSessionInstance;
167}
168
169
170/*static*/ CredentialsStorage*
171CredentialsStorage::PersistentInstance()
172{
173	if (sPersistentInstance.Lock()) {
174		sPersistentInstance._LoadSettings();
175		sPersistentInstance.Unlock();
176	}
177	return &sPersistentInstance;
178}
179
180
181bool
182CredentialsStorage::Contains(const HashKeyString& key)
183{
184	BAutolock _(this);
185
186	return fCredentialMap.ContainsKey(key);
187}
188
189
190status_t
191CredentialsStorage::PutCredentials(const HashKeyString& key,
192	const Credentials& credentials)
193{
194	BAutolock _(this);
195
196	return fCredentialMap.Put(key, credentials);
197}
198
199
200Credentials
201CredentialsStorage::GetCredentials(const HashKeyString& key)
202{
203	BAutolock _(this);
204
205	return fCredentialMap.Get(key);
206}
207
208
209// #pragma mark - private
210
211
212void
213CredentialsStorage::_LoadSettings()
214{
215	if (!fPersistent || fSettingsLoaded)
216		return;
217
218	fSettingsLoaded = true;
219
220	BFile settingsFile;
221	if (_OpenSettingsFile(settingsFile, B_READ_ONLY)) {
222		BMessage settingsArchive;
223		settingsArchive.Unflatten(&settingsFile);
224		BMessage credentialsArchive;
225		for (int32 i = 0; settingsArchive.FindMessage("credentials", i,
226				&credentialsArchive) == B_OK; i++) {
227			BString key;
228			if (credentialsArchive.FindString("key", &key) == B_OK) {
229				Credentials credentials(&credentialsArchive);
230				fCredentialMap.Put(key, credentials);
231			}
232		}
233	}
234}
235
236
237void
238CredentialsStorage::_SaveSettings() const
239{
240	BFile settingsFile;
241	if (_OpenSettingsFile(settingsFile,
242			B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY)) {
243		BMessage settingsArchive;
244		BMessage credentialsArchive;
245		CredentialMap::Iterator iterator = fCredentialMap.GetIterator();
246		while (iterator.HasNext()) {
247			const CredentialMap::Entry& entry = iterator.Next();
248			if (entry.value.Archive(&credentialsArchive) != B_OK
249				|| credentialsArchive.AddString("key",
250					entry.key.value) != B_OK) {
251				break;
252			}
253			if (settingsArchive.AddMessage("credentials",
254					&credentialsArchive) != B_OK) {
255				break;
256			}
257			credentialsArchive.MakeEmpty();
258		}
259		settingsArchive.Flatten(&settingsFile);
260	}
261}
262
263
264bool
265CredentialsStorage::_OpenSettingsFile(BFile& file, uint32 mode) const
266{
267	BPath path;
268	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK
269		|| path.Append(kApplicationName) != B_OK
270		|| path.Append("CredentialsStorage") != B_OK) {
271		return false;
272	}
273	return file.SetTo(path.Path(), mode) == B_OK;
274}
275
276