|
1 /* |
|
2 * Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of the License "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 #include "config.h" |
|
19 #include "StringHash.h" |
|
20 #include "FormLoginStore.h" |
|
21 #include "FileStreamSymbian.h" |
|
22 #include <pbe.h> |
|
23 #include <pbedata.h> |
|
24 _LIT(KLoginDatFile, "c:\\private\\%08x\\login.dat"); |
|
25 |
|
26 namespace WebCore { |
|
27 |
|
28 //------------------------------------------------------------------------------ |
|
29 // LoginData |
|
30 //------------------------------------------------------------------------------ |
|
31 LoginData::LoginData(FormLoginStore* s) : m_store(s) |
|
32 { |
|
33 } |
|
34 |
|
35 LoginData::LoginData(FormLoginStore* s, const String& realm, const String& uname, const String& uvalue, const String& pname, const String& pvalue) |
|
36 : m_realm(realm), m_usernameField(uname), m_usernameValue(uvalue), m_passwdField(pname), m_passwdValue(pvalue), m_store(s) |
|
37 { |
|
38 } |
|
39 |
|
40 LoginData::~LoginData() |
|
41 { |
|
42 } |
|
43 |
|
44 void LoginData::read(StreamInput& is) |
|
45 { |
|
46 String encryptedUser, encryptedPasswd; |
|
47 is>>m_realm>>m_usernameField>>encryptedUser>>m_passwdField>>encryptedPasswd; |
|
48 m_usernameValue = m_store->decrypt(encryptedUser); |
|
49 m_passwdValue = m_store->decrypt(encryptedPasswd); |
|
50 } |
|
51 |
|
52 void LoginData::write(StreamOutput& os) const |
|
53 { |
|
54 os<<m_realm<<m_usernameField<<m_store->encrypt(m_usernameValue)<<m_passwdField<<m_store->encrypt(m_passwdValue); |
|
55 } |
|
56 |
|
57 bool LoginData::partialMatch(const String& realm, const String& uname, const String& uvalue, const String& pname) const |
|
58 { |
|
59 return !(realm != m_realm || uname != m_usernameField || uvalue != m_usernameValue || pname != m_passwdField); |
|
60 } |
|
61 |
|
62 bool LoginData::match(const LoginData& b) const |
|
63 { |
|
64 return partialMatch(b.m_realm, b.m_usernameField, b.m_usernameValue, b.m_passwdField) && (m_passwdValue == b.m_passwdValue); |
|
65 } |
|
66 |
|
67 //------------------------------------------------------------------------------ |
|
68 // FormLoginStore |
|
69 //------------------------------------------------------------------------------ |
|
70 FormLoginStore::FormLoginStore() : m_needCommit(false), m_pbEncrypt(0), m_pbDecrypt(0) |
|
71 { |
|
72 initialize(); |
|
73 } |
|
74 |
|
75 FormLoginStore::~FormLoginStore() |
|
76 { |
|
77 commit(); |
|
78 clearCache(); |
|
79 delete m_pbEncrypt; |
|
80 delete m_pbDecrypt; |
|
81 } |
|
82 |
|
83 void FormLoginStore::setSaveNotAllowed(const String& url) |
|
84 { |
|
85 m_blackList.add(url); |
|
86 } |
|
87 |
|
88 bool FormLoginStore::saveAllowed(const String& url) const |
|
89 { |
|
90 return !m_blackList.contains(url); |
|
91 } |
|
92 |
|
93 void FormLoginStore::add(const String& realm, const String& uname, const String& uvalue, const String& pname, const String& pvalue) |
|
94 { |
|
95 LoginData* login = new LoginData(this, realm, uname, uvalue, pname, pvalue); |
|
96 HashSet<LoginData*>::iterator it = m_logins.begin(), end = m_logins.end(); |
|
97 for (; it!=end; ++it) { |
|
98 if ((*it)->match(*login)) { |
|
99 delete login; |
|
100 return; |
|
101 } else if((*it)->partialMatch(realm, uname, uvalue, pname)) { |
|
102 // new password for the same login |
|
103 m_logins.remove(it); |
|
104 m_logins.add(login); |
|
105 m_needCommit = true; |
|
106 return; |
|
107 } |
|
108 } |
|
109 |
|
110 // new entry |
|
111 m_logins.add(login); |
|
112 m_needCommit = true; |
|
113 } |
|
114 |
|
115 void FormLoginStore::remove(const String& realm, const String& uname, const String& uvalue, const String& pname, const String& pvalue) |
|
116 { |
|
117 LoginData login(this, realm, uname, uvalue, pname, pvalue); |
|
118 HashSet<LoginData*>::iterator it = m_logins.begin(), end = m_logins.end(); |
|
119 for (; it!=end; ++it) { |
|
120 if ((*it)->match(login)) { |
|
121 break; |
|
122 } |
|
123 } |
|
124 |
|
125 if (it!=end) { |
|
126 m_logins.remove(it); |
|
127 m_needCommit = true; |
|
128 } |
|
129 } |
|
130 |
|
131 void FormLoginStore::removePartial(const String& realm, const String& uname, const String& uvalue, const String& pname) |
|
132 { |
|
133 HashSet<LoginData*>::iterator it = m_logins.begin(), end = m_logins.end(); |
|
134 for(; it!=end; ++it) { |
|
135 if ((*it)->partialMatch(realm, uname, uvalue, pname)) { |
|
136 m_logins.remove(it); |
|
137 m_needCommit = true; |
|
138 return; |
|
139 } |
|
140 } |
|
141 } |
|
142 |
|
143 bool FormLoginStore::contains(const String& realm, const String& uname, const String& uvalue, const String& pname, const String& pvalue) |
|
144 { |
|
145 LoginData login(this, realm, uname, uvalue, pname, pvalue); |
|
146 HashSet<LoginData*>::iterator it = m_logins.begin(), end = m_logins.end(); |
|
147 for (; it!=end; ++it) { |
|
148 if ((*it)->match(login)) { |
|
149 return true; |
|
150 } |
|
151 } |
|
152 return false; |
|
153 } |
|
154 |
|
155 void FormLoginStore::removeLoginsForRealm(const String& realm) |
|
156 { |
|
157 HashSet<LoginData*>::iterator it = m_logins.begin(), end = m_logins.end(); |
|
158 Vector<LoginData*> loginsToDelete; |
|
159 |
|
160 for (; it!=end; ++it) { |
|
161 if( (*it)->realm() == realm ) { |
|
162 loginsToDelete.append( *it ); |
|
163 } |
|
164 } |
|
165 |
|
166 for (int i=0; i<loginsToDelete.size(); ++i) { |
|
167 m_logins.remove(loginsToDelete[i]); |
|
168 m_needCommit = true; |
|
169 } |
|
170 } |
|
171 |
|
172 bool FormLoginStore::search(const String& realm, const String& uname, const String& uvalue, const String& pname, String& pvalue) |
|
173 { |
|
174 HashSet<LoginData*>::const_iterator it = m_logins.begin(), end = m_logins.end(); |
|
175 for (; it != end; ++it) { |
|
176 if ((*it)->partialMatch(realm, uname, uvalue, pname)) { |
|
177 pvalue = (*it)->passwdValue(); |
|
178 return true; |
|
179 } |
|
180 } |
|
181 return false; |
|
182 } |
|
183 |
|
184 // login file format: (Note: this is not the most compact format, |
|
185 // however we need to keep it this way in order to be backward compatible.) |
|
186 // |
|
187 // # of blacklist entries |
|
188 // url #1 |
|
189 // url #2 |
|
190 // ... |
|
191 // # of logins |
|
192 // encryption data for logins |
|
193 // #1 realm, usernamefield, usernamevalue, passwdfield, passwdvalue |
|
194 // #2 realm, usernamefield, usernamevalue, passwdfield, passwdvalue |
|
195 // ... |
|
196 void FormLoginStore::commit() |
|
197 { |
|
198 if (!m_needCommit) return; |
|
199 |
|
200 RProcess myProcess; |
|
201 TBuf <256>fileName; |
|
202 fileName.Format(KLoginDatFile, myProcess.Identity()); |
|
203 String s(fileName.Ptr(), fileName.Length()); |
|
204 FileStreamOutput stream(s); |
|
205 |
|
206 if (stream.isOpened()) { |
|
207 // blacklist |
|
208 stream<<(m_blackList.size()); |
|
209 for (HashSet<String>::const_iterator it=m_blackList.begin(), end = m_blackList.end(); it != end; ++it) { |
|
210 stream<<(*it); |
|
211 } |
|
212 |
|
213 // login count |
|
214 stream<<(m_logins.size()); |
|
215 |
|
216 // write the encryption data if we have logins |
|
217 if (m_logins.size()>0) { |
|
218 if (!m_pbEncrypt) |
|
219 m_pbEncrypt = CPBEncryptElement::NewL(_L8(""), ECipher3DES_CBC); |
|
220 m_pbEncrypt->EncryptionData().ExternalizeL(stream.platformStream()); |
|
221 } |
|
222 |
|
223 // now logins |
|
224 for (HashSet<LoginData*>::const_iterator it=m_logins.begin(), end = m_logins.end(); it != end; ++it) { |
|
225 stream<<(*(*it)); |
|
226 } |
|
227 |
|
228 delete m_pbEncrypt; |
|
229 m_pbEncrypt = 0; |
|
230 } |
|
231 |
|
232 m_needCommit = false; |
|
233 } |
|
234 |
|
235 void FormLoginStore::initialize() |
|
236 { |
|
237 RProcess myProcess; |
|
238 TBuf <256>fileName; |
|
239 fileName.Format(KLoginDatFile, myProcess.Identity()); |
|
240 String s(fileName.Ptr(), fileName.Length()); |
|
241 FileStreamInput stream(s); |
|
242 |
|
243 if (stream.isOpened()) { |
|
244 // black-list |
|
245 int bsize = 0; |
|
246 stream>>bsize; |
|
247 for (int i=0; i<bsize; ++i) { |
|
248 String realm; |
|
249 stream>>realm; |
|
250 m_blackList.add(realm); |
|
251 } |
|
252 |
|
253 // logins |
|
254 int lsize = 0; |
|
255 stream>>lsize; |
|
256 |
|
257 CPBEncryptionData* encryptionData = 0; |
|
258 if (lsize) { |
|
259 // prepare for decryption |
|
260 encryptionData = CPBEncryptionData::NewL(stream.platformStream()); |
|
261 if (!m_pbDecrypt) |
|
262 m_pbDecrypt = CPBEncryptElement::NewL(*encryptionData, _L("")); |
|
263 } |
|
264 |
|
265 for (int i=0; i<lsize; ++i) { |
|
266 LoginData* d = new LoginData(this); |
|
267 stream>>(*d); |
|
268 m_logins.add(d); |
|
269 } |
|
270 |
|
271 // encryptionData is not needed any more |
|
272 delete encryptionData; |
|
273 delete m_pbDecrypt; |
|
274 m_pbDecrypt = 0; |
|
275 } |
|
276 } |
|
277 |
|
278 void FormLoginStore::clearCache() |
|
279 { |
|
280 m_blackList.clear(); |
|
281 HashSet<LoginData*>::const_iterator it = m_logins.begin(), end = m_logins.end(); |
|
282 for(; it!=end; ++it) |
|
283 delete (*it); |
|
284 m_logins.clear(); |
|
285 } |
|
286 |
|
287 void FormLoginStore::deleteAll() |
|
288 { |
|
289 // clear the file data |
|
290 clearCache(); |
|
291 m_needCommit = true; |
|
292 commit(); |
|
293 } |
|
294 |
|
295 String FormLoginStore::encrypt(const String& src) |
|
296 { |
|
297 if (!m_pbEncrypt) |
|
298 return src; |
|
299 |
|
300 CPBEncryptor* encryptor = m_pbEncrypt->NewEncryptLC(); |
|
301 int len = encryptor->MaxFinalOutputLength(src.length()<<1); |
|
302 UChar* data = new UChar[len>>1]; |
|
303 TPtrC8 in((const TUint8*)(src.characters()), src.length()<<1); |
|
304 TPtr8 out((TUint8*)data, 0, len); |
|
305 encryptor->ProcessFinalL(in, out); |
|
306 CleanupStack::Pop(); // encryptor |
|
307 delete encryptor; |
|
308 |
|
309 String result(data, len>>1); |
|
310 delete data; |
|
311 |
|
312 return result; |
|
313 } |
|
314 |
|
315 String FormLoginStore::decrypt(const String& src) |
|
316 { |
|
317 if (!m_pbDecrypt) |
|
318 return src; |
|
319 |
|
320 CPBDecryptor* decryptor = m_pbDecrypt->NewDecryptLC(); |
|
321 int len = decryptor->MaxFinalOutputLength(src.length()<<1); |
|
322 len += (len&0x01); |
|
323 UChar* data = new UChar[len>>1]; |
|
324 memset(data, 0x00, len); |
|
325 TPtrC8 in((const TUint8*)(src.characters()), src.length()<<1); |
|
326 TPtr8 out((TUint8*)data, 0, len); |
|
327 decryptor->ProcessFinalL(in, out); |
|
328 CleanupStack::Pop(); // decryptor |
|
329 delete decryptor; |
|
330 |
|
331 // now figure out the padding position |
|
332 int sz=0; |
|
333 for (int i=0; i<len>>1; ++i) { |
|
334 if (data[i] == 0) break; |
|
335 sz++; |
|
336 } |
|
337 |
|
338 String result(data, sz); |
|
339 delete data; |
|
340 |
|
341 return result; |
|
342 } |
|
343 |
|
344 } |