Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 package org.mozilla.gecko.db;
7 import java.util.HashMap;
9 import org.mozilla.gecko.GeckoApp;
10 import org.mozilla.gecko.GeckoAppShell;
11 import org.mozilla.gecko.GeckoEvent;
12 import org.mozilla.gecko.NSSBridge;
13 import org.mozilla.gecko.db.BrowserContract.DeletedPasswords;
14 import org.mozilla.gecko.db.BrowserContract.Passwords;
15 import org.mozilla.gecko.mozglue.GeckoLoader;
16 import org.mozilla.gecko.sqlite.MatrixBlobCursor;
17 import org.mozilla.gecko.sqlite.SQLiteBridge;
18 import org.mozilla.gecko.sync.Utils;
20 import android.content.ContentValues;
21 import android.content.Intent;
22 import android.content.UriMatcher;
23 import android.database.Cursor;
24 import android.net.Uri;
25 import android.text.TextUtils;
26 import android.util.Log;
28 public class PasswordsProvider extends SQLiteBridgeContentProvider {
29 static final String TABLE_PASSWORDS = "moz_logins";
30 static final String TABLE_DELETED_PASSWORDS = "moz_deleted_logins";
32 private static final String TELEMETRY_TAG = "SQLITEBRIDGE_PROVIDER_PASSWORDS";
34 private static final int PASSWORDS = 100;
35 private static final int DELETED_PASSWORDS = 101;
37 static final String DEFAULT_PASSWORDS_SORT_ORDER = Passwords.HOSTNAME + " ASC";
38 static final String DEFAULT_DELETED_PASSWORDS_SORT_ORDER = DeletedPasswords.TIME_DELETED + " ASC";
40 private static final UriMatcher URI_MATCHER;
42 private static HashMap<String, String> PASSWORDS_PROJECTION_MAP;
43 private static HashMap<String, String> DELETED_PASSWORDS_PROJECTION_MAP;
45 // this should be kept in sync with the version in toolkit/components/passwordmgr/storage-mozStorage.js
46 private static final int DB_VERSION = 5;
47 private static final String DB_FILENAME = "signons.sqlite";
48 private static final String WHERE_GUID_IS_NULL = BrowserContract.DeletedPasswords.GUID + " IS NULL";
49 private static final String WHERE_GUID_IS_VALUE = BrowserContract.DeletedPasswords.GUID + " = ?";
51 private static final String LOG_TAG = "GeckPasswordsProvider";
53 static {
54 URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
56 // content://org.mozilla.gecko.providers.browser/passwords/#
57 URI_MATCHER.addURI(BrowserContract.PASSWORDS_AUTHORITY, "passwords", PASSWORDS);
59 PASSWORDS_PROJECTION_MAP = new HashMap<String, String>();
60 PASSWORDS_PROJECTION_MAP.put(Passwords.ID, Passwords.ID);
61 PASSWORDS_PROJECTION_MAP.put(Passwords.HOSTNAME, Passwords.HOSTNAME);
62 PASSWORDS_PROJECTION_MAP.put(Passwords.HTTP_REALM, Passwords.HTTP_REALM);
63 PASSWORDS_PROJECTION_MAP.put(Passwords.FORM_SUBMIT_URL, Passwords.FORM_SUBMIT_URL);
64 PASSWORDS_PROJECTION_MAP.put(Passwords.USERNAME_FIELD, Passwords.USERNAME_FIELD);
65 PASSWORDS_PROJECTION_MAP.put(Passwords.PASSWORD_FIELD, Passwords.PASSWORD_FIELD);
66 PASSWORDS_PROJECTION_MAP.put(Passwords.ENCRYPTED_USERNAME, Passwords.ENCRYPTED_USERNAME);
67 PASSWORDS_PROJECTION_MAP.put(Passwords.ENCRYPTED_PASSWORD, Passwords.ENCRYPTED_PASSWORD);
68 PASSWORDS_PROJECTION_MAP.put(Passwords.GUID, Passwords.GUID);
69 PASSWORDS_PROJECTION_MAP.put(Passwords.ENC_TYPE, Passwords.ENC_TYPE);
70 PASSWORDS_PROJECTION_MAP.put(Passwords.TIME_CREATED, Passwords.TIME_CREATED);
71 PASSWORDS_PROJECTION_MAP.put(Passwords.TIME_LAST_USED, Passwords.TIME_LAST_USED);
72 PASSWORDS_PROJECTION_MAP.put(Passwords.TIME_PASSWORD_CHANGED, Passwords.TIME_PASSWORD_CHANGED);
73 PASSWORDS_PROJECTION_MAP.put(Passwords.TIMES_USED, Passwords.TIMES_USED);
75 URI_MATCHER.addURI(BrowserContract.PASSWORDS_AUTHORITY, "deleted-passwords", DELETED_PASSWORDS);
77 DELETED_PASSWORDS_PROJECTION_MAP = new HashMap<String, String>();
78 DELETED_PASSWORDS_PROJECTION_MAP.put(DeletedPasswords.ID, DeletedPasswords.ID);
79 DELETED_PASSWORDS_PROJECTION_MAP.put(DeletedPasswords.GUID, DeletedPasswords.GUID);
80 DELETED_PASSWORDS_PROJECTION_MAP.put(DeletedPasswords.TIME_DELETED, DeletedPasswords.TIME_DELETED);
82 // We don't use .loadMozGlue because we're in a different process,
83 // and we just want to reuse code rather than use the loader lock etc.
84 GeckoLoader.doLoadLibrary("mozglue");
85 }
87 public PasswordsProvider() {
88 super(LOG_TAG);
89 }
91 @Override
92 protected String getDBName(){
93 return DB_FILENAME;
94 }
96 @Override
97 protected String getTelemetryPrefix() {
98 return TELEMETRY_TAG;
99 }
101 @Override
102 protected int getDBVersion(){
103 return DB_VERSION;
104 }
106 @Override
107 public String getType(Uri uri) {
108 final int match = URI_MATCHER.match(uri);
110 switch (match) {
111 case PASSWORDS:
112 return Passwords.CONTENT_TYPE;
114 case DELETED_PASSWORDS:
115 return DeletedPasswords.CONTENT_TYPE;
117 default:
118 throw new UnsupportedOperationException("Unknown type " + uri);
119 }
120 }
122 @Override
123 public String getTable(Uri uri) {
124 final int match = URI_MATCHER.match(uri);
125 switch (match) {
126 case DELETED_PASSWORDS:
127 return TABLE_DELETED_PASSWORDS;
129 case PASSWORDS:
130 return TABLE_PASSWORDS;
132 default:
133 throw new UnsupportedOperationException("Unknown table " + uri);
134 }
135 }
137 @Override
138 public String getSortOrder(Uri uri, String aRequested) {
139 if (!TextUtils.isEmpty(aRequested)) {
140 return aRequested;
141 }
143 final int match = URI_MATCHER.match(uri);
144 switch (match) {
145 case DELETED_PASSWORDS:
146 return DEFAULT_DELETED_PASSWORDS_SORT_ORDER;
148 case PASSWORDS:
149 return DEFAULT_PASSWORDS_SORT_ORDER;
151 default:
152 throw new UnsupportedOperationException("Unknown URI " + uri);
153 }
154 }
156 @Override
157 public void setupDefaults(Uri uri, ContentValues values)
158 throws IllegalArgumentException {
159 int match = URI_MATCHER.match(uri);
160 long now = System.currentTimeMillis();
161 switch (match) {
162 case DELETED_PASSWORDS:
163 values.put(DeletedPasswords.TIME_DELETED, now);
165 // Deleted passwords must contain a guid
166 if (!values.containsKey(Passwords.GUID)) {
167 throw new IllegalArgumentException("Must provide a GUID for a deleted password");
168 }
169 break;
171 case PASSWORDS:
172 values.put(Passwords.TIME_CREATED, now);
174 // Generate GUID for new password. Don't override specified GUIDs.
175 if (!values.containsKey(Passwords.GUID)) {
176 String guid = Utils.generateGuid();
177 values.put(Passwords.GUID, guid);
178 }
179 String nowString = new Long(now).toString();
180 DBUtils.replaceKey(values, null, Passwords.HOSTNAME, "");
181 DBUtils.replaceKey(values, null, Passwords.HTTP_REALM, "");
182 DBUtils.replaceKey(values, null, Passwords.FORM_SUBMIT_URL, "");
183 DBUtils.replaceKey(values, null, Passwords.USERNAME_FIELD, "");
184 DBUtils.replaceKey(values, null, Passwords.PASSWORD_FIELD, "");
185 DBUtils.replaceKey(values, null, Passwords.ENCRYPTED_USERNAME, "");
186 DBUtils.replaceKey(values, null, Passwords.ENCRYPTED_PASSWORD, "");
187 DBUtils.replaceKey(values, null, Passwords.ENC_TYPE, "0");
188 DBUtils.replaceKey(values, null, Passwords.TIME_LAST_USED, nowString);
189 DBUtils.replaceKey(values, null, Passwords.TIME_PASSWORD_CHANGED, nowString);
190 DBUtils.replaceKey(values, null, Passwords.TIMES_USED, "0");
191 break;
193 default:
194 throw new UnsupportedOperationException("Unknown URI " + uri);
195 }
196 }
198 @Override
199 public void initGecko() {
200 GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Passwords:Init", null));
201 Intent initIntent = new Intent(GeckoApp.ACTION_INIT_PW);
202 mContext.sendBroadcast(initIntent);
203 }
205 private String doCrypto(String initialValue, Uri uri, Boolean encrypt) {
206 String profilePath = null;
207 if (uri != null) {
208 profilePath = uri.getQueryParameter(BrowserContract.PARAM_PROFILE_PATH);
209 }
211 String result = "";
212 try {
213 if (encrypt) {
214 if (profilePath != null) {
215 result = NSSBridge.encrypt(mContext, profilePath, initialValue);
216 } else {
217 result = NSSBridge.encrypt(mContext, initialValue);
218 }
219 } else {
220 if (profilePath != null) {
221 result = NSSBridge.decrypt(mContext, profilePath, initialValue);
222 } else {
223 result = NSSBridge.decrypt(mContext, initialValue);
224 }
225 }
226 } catch (Exception ex) {
227 Log.e(LOG_TAG, "Error in NSSBridge");
228 throw new RuntimeException(ex);
229 }
230 return result;
231 }
233 @Override
234 public void onPreInsert(ContentValues values, Uri uri, SQLiteBridge db) {
235 if (values.containsKey(Passwords.GUID)) {
236 String guid = values.getAsString(Passwords.GUID);
237 if (guid == null) {
238 db.delete(TABLE_DELETED_PASSWORDS, WHERE_GUID_IS_NULL, null);
239 return;
240 }
241 String[] args = new String[] { guid };
242 db.delete(TABLE_DELETED_PASSWORDS, WHERE_GUID_IS_VALUE, args);
243 }
245 if (values.containsKey(Passwords.ENCRYPTED_PASSWORD)) {
246 String res = doCrypto(values.getAsString(Passwords.ENCRYPTED_PASSWORD), uri, true);
247 values.put(Passwords.ENCRYPTED_PASSWORD, res);
248 values.put(Passwords.ENC_TYPE, Passwords.ENCTYPE_SDR);
249 }
251 if (values.containsKey(Passwords.ENCRYPTED_USERNAME)) {
252 String res = doCrypto(values.getAsString(Passwords.ENCRYPTED_USERNAME), uri, true);
253 values.put(Passwords.ENCRYPTED_USERNAME, res);
254 values.put(Passwords.ENC_TYPE, Passwords.ENCTYPE_SDR);
255 }
256 }
258 @Override
259 public void onPreUpdate(ContentValues values, Uri uri, SQLiteBridge db) {
260 if (values.containsKey(Passwords.ENCRYPTED_PASSWORD)) {
261 String res = doCrypto(values.getAsString(Passwords.ENCRYPTED_PASSWORD), uri, true);
262 values.put(Passwords.ENCRYPTED_PASSWORD, res);
263 values.put(Passwords.ENC_TYPE, Passwords.ENCTYPE_SDR);
264 }
266 if (values.containsKey(Passwords.ENCRYPTED_USERNAME)) {
267 String res = doCrypto(values.getAsString(Passwords.ENCRYPTED_USERNAME), uri, true);
268 values.put(Passwords.ENCRYPTED_USERNAME, res);
269 values.put(Passwords.ENC_TYPE, Passwords.ENCTYPE_SDR);
270 }
271 }
273 @Override
274 public void onPostQuery(Cursor cursor, Uri uri, SQLiteBridge db) {
275 int passwordIndex = -1;
276 int usernameIndex = -1;
277 String profilePath = null;
279 try {
280 passwordIndex = cursor.getColumnIndexOrThrow(Passwords.ENCRYPTED_PASSWORD);
281 } catch(Exception ex) { }
282 try {
283 usernameIndex = cursor.getColumnIndexOrThrow(Passwords.ENCRYPTED_USERNAME);
284 } catch(Exception ex) { }
286 if (passwordIndex > -1 || usernameIndex > -1) {
287 MatrixBlobCursor m = (MatrixBlobCursor)cursor;
288 if (cursor.moveToFirst()) {
289 do {
290 if (passwordIndex > -1) {
291 String decrypted = doCrypto(cursor.getString(passwordIndex), uri, false);;
292 m.set(passwordIndex, decrypted);
293 }
295 if (usernameIndex > -1) {
296 String decrypted = doCrypto(cursor.getString(usernameIndex), uri, false);
297 m.set(usernameIndex, decrypted);
298 }
299 } while(cursor.moveToNext());
300 }
301 }
302 }
303 }