Autopsy  4.19.3
Graphical digital forensics platform for The Sleuth Kit and other tools.
Firefox.java
Go to the documentation of this file.
1 /*
2  *
3  * Autopsy Forensic Browser
4  *
5  * Copyright 2012-2021 Basis Technology Corp.
6  *
7  * Copyright 2012 42six Solutions.
8  * Contact: aebadirad <at> 42six <dot> com
9  * Project Contact/Architect: carrier <at> sleuthkit <dot> org
10  *
11  * Licensed under the Apache License, Version 2.0 (the "License");
12  * you may not use this file except in compliance with the License.
13  * You may obtain a copy of the License at
14  *
15  * http://www.apache.org/licenses/LICENSE-2.0
16  *
17  * Unless required by applicable law or agreed to in writing, software
18  * distributed under the License is distributed on an "AS IS" BASIS,
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  * See the License for the specific language governing permissions and
21  * limitations under the License.
22  */
23 package org.sleuthkit.autopsy.recentactivity;
24 
25 import com.google.gson.JsonArray;
26 import com.google.gson.JsonElement;
27 import com.google.gson.JsonIOException;
28 import com.google.gson.JsonObject;
29 import com.google.gson.JsonParser;
30 import com.google.gson.JsonSyntaxException;
31 import java.io.File;
32 import java.io.FileNotFoundException;
33 import java.io.FileReader;
34 import java.io.IOException;
35 import java.io.UnsupportedEncodingException;
36 import java.net.URLDecoder;
37 import java.util.ArrayList;
38 import java.util.Arrays;
39 import java.util.Collection;
40 import java.util.HashMap;
41 import java.util.HashSet;
42 import java.util.List;
43 import java.util.Set;
44 import java.util.logging.Level;
45 import org.apache.commons.io.FilenameUtils;
46 import org.openide.util.NbBundle;
47 import org.openide.util.NbBundle.Messages;
56 import org.sleuthkit.datamodel.AbstractFile;
57 import org.sleuthkit.datamodel.Blackboard;
58 import org.sleuthkit.datamodel.BlackboardArtifact;
59 import org.sleuthkit.datamodel.BlackboardAttribute;
60 import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
61 import org.sleuthkit.datamodel.Content;
62 import org.sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException;
63 import org.sleuthkit.datamodel.TskCoreException;
64 import org.sleuthkit.datamodel.blackboardutils.WebBrowserArtifactsHelper;
65 
66 @Messages({
67  "Progress_Message_Firefox_History=Firefox History",
68  "Progress_Message_Firefox_Bookmarks=Firefox Bookmarks",
69  "Progress_Message_Firefox_Cookies=Firefox Cookies",
70  "Progress_Message_Firefox_Downloads=Firefox Downloads",
71  "Progress_Message_Firefox_FormHistory=Firefox Form History",
72  "Progress_Message_Firefox_AutoFill=Firefox Auto Fill"
73 })
74 
78 class Firefox extends Extract {
79 
80  private static final Logger logger = Logger.getLogger(Firefox.class.getName());
81  private static final String PLACE_URL_PREFIX = "place:";
82  private static final String HISTORY_QUERY = "SELECT moz_historyvisits.id, url, title, visit_count,(visit_date/1000000) AS visit_date,from_visit,"
83  + "(SELECT url FROM moz_historyvisits history, moz_places places where history.id = moz_historyvisits.from_visit and history.place_id = places.id ) as ref "
84  + "FROM moz_places, moz_historyvisits "
85  + "WHERE moz_places.id = moz_historyvisits.place_id "
86  + "AND hidden = 0"; //NON-NLS
87  private static final String COOKIE_QUERY = "SELECT name,value,host,expiry,(lastAccessed/1000000) AS lastAccessed,(creationTime/1000000) AS creationTime FROM moz_cookies"; //NON-NLS
88  private static final String COOKIE_QUERY_V3 = "SELECT name,value,host,expiry,(lastAccessed/1000000) AS lastAccessed FROM moz_cookies"; //NON-NLS
89  private static final String BOOKMARK_QUERY = "SELECT fk, moz_bookmarks.title, url, (moz_bookmarks.dateAdded/1000000) AS dateAdded FROM moz_bookmarks INNER JOIN moz_places ON moz_bookmarks.fk=moz_places.id"; //NON-NLS
90  private static final String DOWNLOAD_QUERY = "SELECT target, source,(startTime/1000000) AS startTime, maxBytes FROM moz_downloads"; //NON-NLS
91  private static final String DOWNLOAD_QUERY_V24 = "SELECT url, content AS target, (lastModified/1000000) AS lastModified "
92  + " FROM moz_places, moz_annos, moz_anno_attributes "
93  + " WHERE moz_places.id = moz_annos.place_id"
94  + " AND moz_annos.anno_attribute_id = moz_anno_attributes.id"
95  + " AND moz_anno_attributes.name='downloads/destinationFileURI'"; //NON-NLS
96  private static final String FORMHISTORY_QUERY = "SELECT fieldname, value FROM moz_formhistory";
97  private static final String FORMHISTORY_QUERY_V64 = "SELECT fieldname, value, timesUsed, firstUsed, lastUsed FROM moz_formhistory";
98  private Content dataSource;
99  private final IngestJobContext context;
100 
101  Firefox(IngestJobContext context) {
102  super(NbBundle.getMessage(Firefox.class, "Firefox.moduleName"), context);
103  this.context = context;
104  }
105 
106  @Override
107  public void process(Content dataSource, DataSourceIngestModuleProgress progressBar) {
108  this.dataSource = dataSource;
109  dataFound = false;
110  long ingestJobId = context.getJobId();
111 
112  progressBar.progress(Bundle.Progress_Message_Firefox_History());
113  this.getHistory(context.getJobId());
114 
115  if (context.dataSourceIngestIsCancelled()) {
116  return;
117  }
118 
119  progressBar.progress(Bundle.Progress_Message_Firefox_Bookmarks());
120  this.getBookmark(ingestJobId);
121 
122  if (context.dataSourceIngestIsCancelled()) {
123  return;
124  }
125 
126  progressBar.progress(Bundle.Progress_Message_Firefox_Downloads());
127  this.getDownload(ingestJobId);
128 
129  if (context.dataSourceIngestIsCancelled()) {
130  return;
131  }
132 
133  progressBar.progress(Bundle.Progress_Message_Firefox_Cookies());
134  this.getCookie(ingestJobId);
135 
136  if (context.dataSourceIngestIsCancelled()) {
137  return;
138  }
139 
140  progressBar.progress(Bundle.Progress_Message_Firefox_FormHistory());
141  this.getFormsHistory(ingestJobId);
142 
143  if (context.dataSourceIngestIsCancelled()) {
144  return;
145  }
146 
147  progressBar.progress(Bundle.Progress_Message_Firefox_AutoFill());
148  this.getAutofillProfiles(ingestJobId);
149  }
150 
156  private void getHistory(long ingestJobId) {
157  FileManager fileManager = currentCase.getServices().getFileManager();
158  List<AbstractFile> historyFiles;
159  try {
160  historyFiles = fileManager.findFiles(dataSource, "places.sqlite", "Firefox"); //NON-NLS
161  } catch (TskCoreException ex) {
162  String msg = NbBundle.getMessage(this.getClass(), "Firefox.getHistory.errMsg.errFetchingFiles");
163  logger.log(Level.WARNING, msg);
164  this.addErrorMessage(this.getDisplayName() + ": " + msg);
165  return;
166  }
167 
168  if (historyFiles.isEmpty()) {
169  String msg = NbBundle.getMessage(this.getClass(), "Firefox.getHistory.errMsg.noFilesFound");
170  logger.log(Level.INFO, msg);
171  return;
172  }
173 
174  dataFound = true;
175  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
176  int j = 0;
177  for (AbstractFile historyFile : historyFiles) {
178 
179  if (context.dataSourceIngestIsCancelled()) {
180  return;
181  }
182 
183  if (historyFile.getSize() == 0) {
184  continue;
185  }
186 
187  String fileName = historyFile.getName();
188  String temps = RAImageIngestModule.getRATempPath(currentCase, "firefox", ingestJobId) + File.separator + fileName + j + ".db"; //NON-NLS
189  try {
190  ContentUtils.writeToFile(historyFile, new File(temps), context::dataSourceIngestIsCancelled);
191  } catch (ReadContentInputStreamException ex) {
192  logger.log(Level.WARNING, String.format("Error reading Firefox web history artifacts file '%s' (id=%d).",
193  fileName, historyFile.getId()), ex); //NON-NLS
194  this.addErrorMessage(
195  NbBundle.getMessage(this.getClass(), "Firefox.getHistory.errMsg.errAnalyzeFile", this.getDisplayName(),
196  fileName));
197  continue;
198  } catch (IOException ex) {
199  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Firefox web history artifacts file '%s' (id=%d).",
200  temps, fileName, historyFile.getId()), ex); //NON-NLS
201  this.addErrorMessage(
202  NbBundle.getMessage(this.getClass(), "Firefox.getHistory.errMsg.errAnalyzeFile", this.getDisplayName(),
203  fileName));
204  continue;
205  }
206  File dbFile = new File(temps);
207  if (context.dataSourceIngestIsCancelled()) {
208  dbFile.delete();
209  break;
210  }
211  List<HashMap<String, Object>> tempList = this.querySQLiteDb(temps, HISTORY_QUERY);
212  logger.log(Level.INFO, "{0} - Now getting history from {1} with {2} artifacts identified.", new Object[]{getDisplayName(), temps, tempList.size()}); //NON-NLS
213  for (HashMap<String, Object> result : tempList) {
214 
215  if (context.dataSourceIngestIsCancelled()) {
216  return;
217  }
218 
219  String url = result.get("url").toString();
220  String domain = extractDomain(url);
221  try {
222 
223  Collection<BlackboardAttribute> bbattributes = createHistoryAttributes(
224  url,
225  Long.valueOf(result.get("visit_date").toString()),
226  result.get("ref").toString(),
227  result.get("title").toString(),
228  NbBundle.getMessage(this.getClass(), "Firefox.moduleName"),
229  domain,
230  null);
231 
232 
233  bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_HISTORY, historyFile, bbattributes));
234  } catch (TskCoreException ex) {
235  logger.log(Level.SEVERE, String.format("Failed to create TSK_WEB_HISTORY artifact for file %d", historyFile.getId()), ex);
236  }
237  }
238  ++j;
239  dbFile.delete();
240  }
241 
242  if (!context.dataSourceIngestIsCancelled()) {
243  postArtifacts(bbartifacts);
244  }
245  }
246 
252  private void getBookmark(long ingestJobId) {
253 
254  FileManager fileManager = currentCase.getServices().getFileManager();
255  List<AbstractFile> bookmarkFiles;
256  try {
257  bookmarkFiles = fileManager.findFiles(dataSource, "places.sqlite", "Firefox"); //NON-NLS
258  } catch (TskCoreException ex) {
259  String msg = NbBundle.getMessage(this.getClass(), "Firefox.getBookmark.errMsg.errFetchFiles");
260  logger.log(Level.WARNING, msg);
261  this.addErrorMessage(this.getDisplayName() + ": " + msg);
262  return;
263  }
264 
265  if (bookmarkFiles.isEmpty()) {
266  logger.log(Level.INFO, "Didn't find any firefox bookmark files."); //NON-NLS
267  return;
268  }
269 
270  dataFound = true;
271  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
272  int j = 0;
273  for (AbstractFile bookmarkFile : bookmarkFiles) {
274  if (bookmarkFile.getSize() == 0) {
275  continue;
276  }
277  String fileName = bookmarkFile.getName();
278  String temps = RAImageIngestModule.getRATempPath(currentCase, "firefox", ingestJobId) + File.separator + fileName + j + ".db"; //NON-NLS
279  try {
280  ContentUtils.writeToFile(bookmarkFile, new File(temps), context::dataSourceIngestIsCancelled);
281  } catch (ReadContentInputStreamException ex) {
282  logger.log(Level.WARNING, String.format("Error reading Firefox bookmark artifacts file '%s' (id=%d).",
283  fileName, bookmarkFile.getId()), ex); //NON-NLS
284  this.addErrorMessage(
285  NbBundle.getMessage(this.getClass(), "Firefox.getHistory.errMsg.errAnalyzeFile", this.getDisplayName(),
286  fileName));
287  continue;
288  } catch (IOException ex) {
289  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Firefox bookmark artifacts file '%s' (id=%d).",
290  temps, fileName, bookmarkFile.getId()), ex); //NON-NLS
291  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Firefox.getBookmark.errMsg.errAnalyzeFile",
292  this.getDisplayName(), fileName));
293  continue;
294  }
295  File dbFile = new File(temps);
296  if (context.dataSourceIngestIsCancelled()) {
297  dbFile.delete();
298  break;
299  }
300  List<HashMap<String, Object>> tempList = this.querySQLiteDb(temps, BOOKMARK_QUERY);
301  logger.log(Level.INFO, "{0} - Now getting bookmarks from {1} with {2} artifacts identified.", new Object[]{getDisplayName(), temps, tempList.size()}); //NON-NLS
302  for (HashMap<String, Object> result : tempList) {
303 
304  if (context.dataSourceIngestIsCancelled()) {
305  break;
306  }
307 
308  String url = result.get("url").toString();
309 
310  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
311  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
312  RecentActivityExtracterModuleFactory.getModuleName(),
313  ((url != null) ? url : ""))); //NON-NLS
314  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TITLE,
315  RecentActivityExtracterModuleFactory.getModuleName(),
316  ((result.get("title").toString() != null) ? result.get("title").toString() : ""))); //NON-NLS
317  if (Long.valueOf(result.get("dateAdded").toString()) > 0) { //NON-NLS
318  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
319  RecentActivityExtracterModuleFactory.getModuleName(),
320  (Long.valueOf(result.get("dateAdded").toString())))); //NON-NLS
321  }
322  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
323  RecentActivityExtracterModuleFactory.getModuleName(),
324  NbBundle.getMessage(this.getClass(), "Firefox.moduleName")));
325  String domain = extractDomain(url);
326  if (domain != null && domain.isEmpty() == false) {
327  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
328  RecentActivityExtracterModuleFactory.getModuleName(), domain)); //NON-NLS
329  }
330 
331  try {
332  bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_BOOKMARK, bookmarkFile, bbattributes));
333  } catch (TskCoreException ex) {
334  logger.log(Level.SEVERE, String.format("Failed to create TSK_WEB_BOOKMARK artifact for file %d", bookmarkFile.getId()), ex);
335  }
336  }
337  ++j;
338  dbFile.delete();
339  }
340 
341  if (!context.dataSourceIngestIsCancelled()) {
342  postArtifacts(bbartifacts);
343  }
344  }
345 
351  private void getCookie(long ingestJobId) {
352  FileManager fileManager = currentCase.getServices().getFileManager();
353  List<AbstractFile> cookiesFiles;
354  try {
355  cookiesFiles = fileManager.findFiles(dataSource, "cookies.sqlite", "Firefox"); //NON-NLS
356  } catch (TskCoreException ex) {
357  String msg = NbBundle.getMessage(this.getClass(), "Firefox.getCookie.errMsg.errFetchFile");
358  logger.log(Level.WARNING, msg);
359  this.addErrorMessage(this.getDisplayName() + ": " + msg);
360  return;
361  }
362 
363  if (cookiesFiles.isEmpty()) {
364  logger.log(Level.INFO, "Didn't find any Firefox cookie files."); //NON-NLS
365  return;
366  }
367 
368  dataFound = true;
369  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
370  int j = 0;
371  for (AbstractFile cookiesFile : cookiesFiles) {
372  if (context.dataSourceIngestIsCancelled()) {
373  return;
374  }
375 
376  if (cookiesFile.getSize() == 0) {
377  continue;
378  }
379  String fileName = cookiesFile.getName();
380  String temps = RAImageIngestModule.getRATempPath(currentCase, "firefox", ingestJobId) + File.separator + fileName + j + ".db"; //NON-NLS
381  try {
382  ContentUtils.writeToFile(cookiesFile, new File(temps), context::dataSourceIngestIsCancelled);
383  } catch (ReadContentInputStreamException ex) {
384  logger.log(Level.WARNING, String.format("Error reading Firefox cookie artifacts file '%s' (id=%d).",
385  fileName, cookiesFile.getId()), ex); //NON-NLS
386  this.addErrorMessage(
387  NbBundle.getMessage(this.getClass(), "Firefox.getHistory.errMsg.errAnalyzeFile", this.getDisplayName(),
388  fileName));
389  continue;
390  } catch (IOException ex) {
391  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Firefox cookie artifacts file '%s' (id=%d).",
392  temps, fileName, cookiesFile.getId()), ex); //NON-NLS
393  this.addErrorMessage(
394  NbBundle.getMessage(this.getClass(), "Firefox.getCookie.errMsg.errAnalyzeFile", this.getDisplayName(),
395  fileName));
396  continue;
397  }
398  File dbFile = new File(temps);
399  if (context.dataSourceIngestIsCancelled()) {
400  dbFile.delete();
401  break;
402  }
403  boolean checkColumn = Util.checkColumn("creationTime", "moz_cookies", temps); //NON-NLS
404  String query;
405  if (checkColumn) {
406  query = COOKIE_QUERY;
407  } else {
408  query = COOKIE_QUERY_V3;
409  }
410 
411  List<HashMap<String, Object>> tempList = this.querySQLiteDb(temps, query);
412  logger.log(Level.INFO, "{0} - Now getting cookies from {1} with {2} artifacts identified.", new Object[]{getDisplayName(), temps, tempList.size()}); //NON-NLS
413  for (HashMap<String, Object> result : tempList) {
414 
415  if (context.dataSourceIngestIsCancelled()) {
416  break;
417  }
418 
419  String host = result.get("host").toString();
420 
421  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
422  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
423  RecentActivityExtracterModuleFactory.getModuleName(),
424  ((host != null) ? host : ""))); //NON-NLS
425  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
426  RecentActivityExtracterModuleFactory.getModuleName(),
427  (Long.valueOf(result.get("lastAccessed").toString())))); //NON-NLS
428  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
429  RecentActivityExtracterModuleFactory.getModuleName(),
430  ((result.get("name").toString() != null) ? result.get("name").toString() : ""))); //NON-NLS
431  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE,
432  RecentActivityExtracterModuleFactory.getModuleName(),
433  ((result.get("value").toString() != null) ? result.get("value").toString() : ""))); //NON-NLS
434  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
435  RecentActivityExtracterModuleFactory.getModuleName(),
436  NbBundle.getMessage(this.getClass(), "Firefox.moduleName")));
437 
438  if (checkColumn == true) {
439  String value = result.get("creationTime").toString();
440  if(value != null && !value.isEmpty()) {
441  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
442  RecentActivityExtracterModuleFactory.getModuleName(),
443  (Long.valueOf(result.get("creationTime").toString())))); //NON-NLS
444  }
445  }
446  String domain = extractDomain(host);
447  if (domain != null && domain.isEmpty() == false) {
448  domain = domain.replaceFirst("^\\.+(?!$)", "");
449  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
450  RecentActivityExtracterModuleFactory.getModuleName(), domain));
451  }
452 
453  try {
454  bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_COOKIE, cookiesFile, bbattributes));
455  } catch (TskCoreException ex) {
456  logger.log(Level.SEVERE, String.format("Failed to create TSK_WEB_COOKIE artifact for file %d", cookiesFile.getId()), ex);
457  }
458  }
459  ++j;
460  dbFile.delete();
461  }
462 
463  if (!context.dataSourceIngestIsCancelled()) {
464  postArtifacts(bbartifacts);
465  }
466  }
467 
473  private void getDownload(long ingestJobId) {
474  getDownloadPreVersion24(ingestJobId);
475  getDownloadVersion24(ingestJobId);
476  }
477 
485  private void getDownloadPreVersion24(long ingestJobId) {
486 
487  FileManager fileManager = currentCase.getServices().getFileManager();
488  List<AbstractFile> downloadsFiles;
489  try {
490  downloadsFiles = fileManager.findFiles(dataSource, "downloads.sqlite", "Firefox"); //NON-NLS
491  } catch (TskCoreException ex) {
492  String msg = NbBundle.getMessage(this.getClass(), "Firefox.getDlPre24.errMsg.errFetchFiles");
493  logger.log(Level.WARNING, msg);
494  this.addErrorMessage(this.getDisplayName() + ": " + msg);
495  return;
496  }
497 
498  if (downloadsFiles.isEmpty()) {
499  logger.log(Level.INFO, "Didn't find any pre-version-24.0 Firefox download files."); //NON-NLS
500  return;
501  }
502 
503  dataFound = true;
504  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
505  int j = 0;
506  for (AbstractFile downloadsFile : downloadsFiles) {
507  if (downloadsFile.getSize() == 0) {
508  continue;
509  }
510  String fileName = downloadsFile.getName();
511  String temps = RAImageIngestModule.getRATempPath(currentCase, "firefox", ingestJobId) + File.separator + fileName + j + ".db"; //NON-NLS
512  int errors = 0;
513  try {
514  ContentUtils.writeToFile(downloadsFile, new File(temps), context::dataSourceIngestIsCancelled);
515  } catch (ReadContentInputStreamException ex) {
516  logger.log(Level.WARNING, String.format("Error reading Firefox download artifacts file '%s' (id=%d).",
517  fileName, downloadsFile.getId()), ex); //NON-NLS
518  this.addErrorMessage(
519  NbBundle.getMessage(this.getClass(), "Firefox.getHistory.errMsg.errAnalyzeFile", this.getDisplayName(),
520  fileName));
521  continue;
522  } catch (IOException ex) {
523  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Firefox download artifacts file '%s' (id=%d).",
524  temps, fileName, downloadsFile.getId()), ex); //NON-NLS
525  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Firefox.getDlPre24.errMsg.errAnalyzeFiles",
526  this.getDisplayName(), fileName));
527  continue;
528  }
529  File dbFile = new File(temps);
530  if (context.dataSourceIngestIsCancelled()) {
531  dbFile.delete();
532  break;
533  }
534 
535  List<HashMap<String, Object>> tempList = this.querySQLiteDb(temps, DOWNLOAD_QUERY);
536  logger.log(Level.INFO, "{0}- Now getting downloads from {1} with {2} artifacts identified.", new Object[]{getDisplayName(), temps, tempList.size()}); //NON-NLS
537  for (HashMap<String, Object> result : tempList) {
538 
539  if (context.dataSourceIngestIsCancelled()) {
540  break;
541  }
542 
543  String source = result.get("source").toString();
544 
545  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
546 
547  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
548  RecentActivityExtracterModuleFactory.getModuleName(),
549  source)); //NON-NLS
550  //bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "RecentActivity", ((result.get("source").toString() != null) ? EscapeUtil.decodeURL(result.get("source").toString()) : "")));
551  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
552  RecentActivityExtracterModuleFactory.getModuleName(),
553  (Long.valueOf(result.get("startTime").toString())))); //NON-NLS
554 
555  String target = result.get("target").toString(); //NON-NLS
556  String downloadedFilePath = "";
557  if (target != null) {
558  try {
559  downloadedFilePath = URLDecoder.decode(target.replaceAll("file:///", ""), "UTF-8"); //NON-NLS
560  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH,
561  RecentActivityExtracterModuleFactory.getModuleName(),
562  downloadedFilePath));
563  long pathID = Util.findID(dataSource, downloadedFilePath);
564  if (pathID != -1) {
565  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH_ID,
566  RecentActivityExtracterModuleFactory.getModuleName(),
567  pathID));
568  }
569  } catch (UnsupportedEncodingException ex) {
570  logger.log(Level.SEVERE, "Error decoding Firefox download URL in " + temps, ex); //NON-NLS
571  errors++;
572  }
573  }
574 
575  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
576  RecentActivityExtracterModuleFactory.getModuleName(),
577  NbBundle.getMessage(this.getClass(), "Firefox.moduleName")));
578  String domain = extractDomain(source);
579  if (domain != null && domain.isEmpty() == false) {
580  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
581  RecentActivityExtracterModuleFactory.getModuleName(),
582  domain)); //NON-NLS
583  }
584  try {
585  BlackboardArtifact webDownloadArtifact = createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_DOWNLOAD, downloadsFile, bbattributes);
586  bbartifacts.add(webDownloadArtifact);
587 
588  // find the downloaded file and create a TSK_ASSOCIATED_OBJECT for it, associating it with the TSK_WEB_DOWNLOAD artifact.
589  for (AbstractFile downloadedFile : currentCase.getSleuthkitCase().getFileManager().findFilesExactNameExactPath(dataSource,
590  FilenameUtils.getName(downloadedFilePath), FilenameUtils.getPath(downloadedFilePath))) {
591  bbartifacts.add(createAssociatedArtifact(downloadedFile, webDownloadArtifact));
592  break;
593  }
594  } catch (TskCoreException ex) {
595  logger.log(Level.SEVERE, String.format("Error creating TSK_WEB_DOWNLOAD or TSK_ASSOCIATED_ARTIFACT artifact for file '%d'",
596  downloadsFile.getId()), ex); //NON-NLS
597  }
598 
599  }
600  if (errors > 0) {
601  this.addErrorMessage(
602  NbBundle.getMessage(this.getClass(), "Firefox.getDlPre24.errMsg.errParsingArtifacts",
603  this.getDisplayName(), errors));
604  }
605  j++;
606  dbFile.delete();
607  }
608 
609  if (!context.dataSourceIngestIsCancelled()) {
610  postArtifacts(bbartifacts);
611  }
612  }
613 
621  private void getDownloadVersion24(long ingestJobId) {
622  FileManager fileManager = currentCase.getServices().getFileManager();
623  List<AbstractFile> downloadsFiles;
624  try {
625  downloadsFiles = fileManager.findFiles(dataSource, "places.sqlite", "Firefox"); //NON-NLS
626  } catch (TskCoreException ex) {
627  String msg = NbBundle.getMessage(this.getClass(), "Firefox.getDlV24.errMsg.errFetchFiles");
628  logger.log(Level.WARNING, msg);
629  this.addErrorMessage(this.getDisplayName() + ": " + msg);
630  return;
631  }
632 
633  if (downloadsFiles.isEmpty()) {
634  logger.log(Level.INFO, "Didn't find any version-24.0 Firefox download files."); //NON-NLS
635  return;
636  }
637 
638  dataFound = true;
639  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
640  int j = 0;
641  for (AbstractFile downloadsFile : downloadsFiles) {
642  if (downloadsFile.getSize() == 0) {
643  continue;
644  }
645  String fileName = downloadsFile.getName();
646  String temps = RAImageIngestModule.getRATempPath(currentCase, "firefox", ingestJobId) + File.separator + fileName + "-downloads" + j + ".db"; //NON-NLS
647  int errors = 0;
648  try {
649  ContentUtils.writeToFile(downloadsFile, new File(temps), context::dataSourceIngestIsCancelled);
650  } catch (ReadContentInputStreamException ex) {
651  logger.log(Level.WARNING, String.format("Error reading Firefox download artifacts file '%s' (id=%d).",
652  fileName, downloadsFile.getId()), ex); //NON-NLS
653  this.addErrorMessage(
654  NbBundle.getMessage(this.getClass(), "Firefox.getHistory.errMsg.errAnalyzeFile", this.getDisplayName(),
655  fileName));
656  continue;
657  } catch (IOException ex) {
658  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Firefox download artifacts file '%s' (id=%d).",
659  temps, fileName, downloadsFile.getId()), ex); //NON-NLS
660  this.addErrorMessage(
661  NbBundle.getMessage(this.getClass(), "Firefox.getDlV24.errMsg.errAnalyzeFile", this.getDisplayName(),
662  fileName));
663  continue;
664  }
665  File dbFile = new File(temps);
666  if (context.dataSourceIngestIsCancelled()) {
667  dbFile.delete();
668  break;
669  }
670 
671  List<HashMap<String, Object>> tempList = this.querySQLiteDb(temps, DOWNLOAD_QUERY_V24);
672 
673  logger.log(Level.INFO, "{0} - Now getting downloads from {1} with {2} artifacts identified.", new Object[]{getDisplayName(), temps, tempList.size()}); //NON-NLS
674  for (HashMap<String, Object> result : tempList) {
675 
676  if (context.dataSourceIngestIsCancelled()) {
677  break;
678  }
679 
680  String url = result.get("url").toString();
681 
682  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
683 
684  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
685  RecentActivityExtracterModuleFactory.getModuleName(),
686  url)); //NON-NLS
687  //bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "RecentActivity", ((result.get("source").toString() != null) ? EscapeUtil.decodeURL(result.get("source").toString()) : "")));
688  //TODO Revisit usage of deprecated constructor as per TSK-583
689  //bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LAST_ACCESSED.getTypeID(), "RecentActivity", "Last Visited", (Long.valueOf(result.get("startTime").toString()))));
690 
691  String target = result.get("target").toString(); //NON-NLS
692  String downloadedFilePath = "";
693  if (target != null) {
694  try {
695  downloadedFilePath = URLDecoder.decode(target.replaceAll("file:///", ""), "UTF-8"); //NON-NLS
696  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH,
697  RecentActivityExtracterModuleFactory.getModuleName(),
698  downloadedFilePath));
699  long pathID = Util.findID(dataSource, downloadedFilePath);
700  if (pathID != -1) {
701  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH_ID,
702  RecentActivityExtracterModuleFactory.getModuleName(),
703  pathID));
704  }
705  } catch (UnsupportedEncodingException ex) {
706  logger.log(Level.SEVERE, "Error decoding Firefox download URL in " + temps, ex); //NON-NLS
707  errors++;
708  }
709  }
710  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
711  RecentActivityExtracterModuleFactory.getModuleName(),
712  Long.valueOf(result.get("lastModified").toString()))); //NON-NLS
713  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
714  RecentActivityExtracterModuleFactory.getModuleName(),
715  NbBundle.getMessage(this.getClass(), "Firefox.moduleName")));
716  String domain = extractDomain(url);
717  if (domain != null && domain.isEmpty() == false) {
718  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
719  RecentActivityExtracterModuleFactory.getModuleName(), domain)); //NON-NLS
720  }
721  try {
722  BlackboardArtifact webDownloadArtifact = createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_DOWNLOAD, downloadsFile, bbattributes);
723  bbartifacts.add(webDownloadArtifact);
724 
725  // find the downloaded file and create a TSK_ASSOCIATED_OBJECT for it, associating it with the TSK_WEB_DOWNLOAD artifact.
726  for (AbstractFile downloadedFile : currentCase.getSleuthkitCase().getFileManager().findFilesExactNameExactPath(dataSource,
727  FilenameUtils.getName(downloadedFilePath), FilenameUtils.getPath(downloadedFilePath))) {
728  bbartifacts.add(createAssociatedArtifact(downloadedFile, webDownloadArtifact));
729  break;
730  }
731  } catch (TskCoreException ex) {
732  logger.log(Level.SEVERE, String.format("Error creating associated object artifact for file '%s'",
733  downloadedFilePath), ex); //NON-NLS
734  }
735  }
736  if (errors > 0) {
737  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Firefox.getDlV24.errMsg.errParsingArtifacts",
738  this.getDisplayName(), errors));
739  }
740  j++;
741  dbFile.delete();
742  }
743 
744  if (!context.dataSourceIngestIsCancelled()) {
745  postArtifacts(bbartifacts);
746  }
747  }
748 
755  private void getFormsHistory(long ingestJobId) {
756  FileManager fileManager = currentCase.getServices().getFileManager();
757  List<AbstractFile> formHistoryFiles;
758 
759  // Some fields are just noisy and can me excluded
760  Set<String> excludedFieldNames = new HashSet<>(Arrays.asList(
761  "it", // some kind of timestamp
762  "ts" // some kind of timestamp
763  ));
764 
765  try {
766  formHistoryFiles = fileManager.findFiles(dataSource, "formhistory.sqlite", "Firefox"); //NON-NLS
767  } catch (TskCoreException ex) {
768  String msg = NbBundle.getMessage(this.getClass(), "Firefox.getFormsAutofill.errMsg.errFetchingFiles");
769  logger.log(Level.WARNING, msg);
770  this.addErrorMessage(this.getDisplayName() + ": " + msg);
771  return;
772  }
773 
774  if (formHistoryFiles.isEmpty()) {
775  String msg = NbBundle.getMessage(this.getClass(), "Firefox.getFormsAutofill.errMsg.noFilesFound");
776  logger.log(Level.INFO, msg);
777  return;
778  }
779 
780  dataFound = true;
781  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
782  int j = 0;
783  for (AbstractFile formHistoryFile : formHistoryFiles) {
784  if (formHistoryFile.getSize() == 0) {
785  continue;
786  }
787 
788  String fileName = formHistoryFile.getName();
789  String tempFilePath = RAImageIngestModule.getRATempPath(currentCase, "firefox", ingestJobId) + File.separator + fileName + j + ".db"; //NON-NLS
790  try {
791  ContentUtils.writeToFile(formHistoryFile, new File(tempFilePath), context::dataSourceIngestIsCancelled);
792  } catch (ReadContentInputStreamException ex) {
793  logger.log(Level.WARNING, String.format("Error reading Firefox web history artifacts file '%s' (id=%d).",
794  fileName, formHistoryFile.getId()), ex); //NON-NLS
795  this.addErrorMessage(
796  NbBundle.getMessage(this.getClass(), "Firefox.getFormsAutofill.errMsg.errAnalyzeFile", this.getDisplayName(),
797  fileName));
798  continue;
799  } catch (IOException ex) {
800  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Firefox web history artifacts file '%s' (id=%d).",
801  tempFilePath, fileName, formHistoryFile.getId()), ex); //NON-NLS
802  this.addErrorMessage(
803  NbBundle.getMessage(this.getClass(), "Firefox.getFormsAutofill.errMsg.errAnalyzeFile", this.getDisplayName(),
804  fileName));
805  continue;
806  }
807  File dbFile = new File(tempFilePath);
808  if (context.dataSourceIngestIsCancelled()) {
809  dbFile.delete();
810  break;
811  }
812 
813  // The table schema is a little different in newer version of Firefox
814  boolean isFirefoxV64 = Util.checkColumn("timesUsed", "moz_formhistory", tempFilePath);
815  String formHistoryQuery = (isFirefoxV64) ? FORMHISTORY_QUERY_V64 : FORMHISTORY_QUERY;
816 
817  List<HashMap<String, Object>> tempList = this.querySQLiteDb(tempFilePath, formHistoryQuery);
818  logger.log(Level.INFO, "{0} - Now getting history from {1} with {2} artifacts identified.", new Object[]{getDisplayName(), tempFilePath, tempList.size()}); //NON-NLS
819  for (HashMap<String, Object> result : tempList) {
820 
821  if (context.dataSourceIngestIsCancelled()) {
822  break;
823  }
824 
825  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
826 
827  String fieldName = ((result.get("fieldname").toString() != null) ? result.get("fieldname").toString() : "");
828  // filter out unuseful values
829  if (excludedFieldNames.contains(fieldName.toLowerCase())) {
830  continue;
831  }
832 
833  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
834  RecentActivityExtracterModuleFactory.getModuleName(),
835  fieldName)); //NON-NLS
836 
837  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE,
838  RecentActivityExtracterModuleFactory.getModuleName(),
839  ((result.get("value").toString() != null) ? result.get("value").toString() : ""))); //NON-NLS
840 
841  // Newer versions of firefox have additional columns
842  if (isFirefoxV64) {
843  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
844  RecentActivityExtracterModuleFactory.getModuleName(),
845  (Long.valueOf(result.get("firstUsed").toString()) / 1000000))); //NON-NLS
846 
847  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
848  RecentActivityExtracterModuleFactory.getModuleName(),
849  (Long.valueOf(result.get("lastUsed").toString()) / 1000000))); //NON-NLS
850 
851  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNT,
852  RecentActivityExtracterModuleFactory.getModuleName(),
853  (Integer.valueOf(result.get("timesUsed").toString())))); //NON-NLS
854 
855  }
856  try {
857  // Add artifact
858  bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_FORM_AUTOFILL, formHistoryFile, bbattributes));
859  } catch (TskCoreException ex) {
860  logger.log(Level.SEVERE, String.format("Failed to create TSK_WEB_FORM_AUTOFILL artifact for file %d", formHistoryFile.getId()), ex);
861  }
862  }
863  ++j;
864  dbFile.delete();
865  }
866 
867  if (!context.dataSourceIngestIsCancelled()) {
868  postArtifacts(bbartifacts);
869  }
870  }
871 
878  private void getAutofillProfiles(long ingestJobId) {
879  FileManager fileManager = currentCase.getServices().getFileManager();
880  List<AbstractFile> autofillProfilesFiles;
881  try {
882  autofillProfilesFiles = fileManager.findFiles(dataSource, "autofill-profiles.json", "Firefox"); //NON-NLS
883  } catch (TskCoreException ex) {
884  String msg = NbBundle.getMessage(this.getClass(), "Firefox.getAutofillProfiles.errMsg.errGettingFiles");
885  logger.log(Level.SEVERE, msg, ex);
886  this.addErrorMessage(this.getDisplayName() + ": " + msg);
887  return;
888  }
889 
890  if (autofillProfilesFiles.isEmpty()) {
891  logger.log(Level.INFO, "Didn't find any Firefox Autofill Profiles files."); //NON-NLS
892  return;
893  }
894 
895  dataFound = true;
896  int j = 0;
897  while (j < autofillProfilesFiles.size()) {
898  AbstractFile profileFile = autofillProfilesFiles.get(j++);
899  if (profileFile.getSize() == 0) {
900  continue;
901  }
902  String temps = RAImageIngestModule.getRATempPath(currentCase, "Firefox", ingestJobId) + File.separator + profileFile.getName() + j + ".json"; //NON-NLS
903  try {
904  ContentUtils.writeToFile(profileFile, new File(temps), context::dataSourceIngestIsCancelled);
905  } catch (ReadContentInputStreamException ex) {
906  logger.log(Level.WARNING, String.format("Error reading Firefox Autofill profiles artifacts file '%s' (id=%d).",
907  profileFile.getName(), profileFile.getId()), ex); //NON-NLS
908  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Firefox.getAutofillProfiles.errMsg.errAnalyzingFile",
909  this.getDisplayName(), profileFile.getName()));
910  continue;
911  } catch (IOException ex) {
912  logger.log(Level.SEVERE, String.format("Error writing temp file '%s' for Firefox Autofill profiles file '%s' (id=%d).",
913  temps, profileFile.getName(), profileFile.getId()), ex); //NON-NLS
914  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Firefox.getAutofillProfiles.errMsg.errAnalyzingFile",
915  this.getDisplayName(), profileFile.getName()));
916  continue;
917  }
918 
919  logger.log(Level.INFO, "{0}- Now getting Bookmarks from {1}", new Object[]{getDisplayName(), temps}); //NON-NLS
920  File dbFile = new File(temps);
921  if (context.dataSourceIngestIsCancelled()) {
922  dbFile.delete();
923  break;
924  }
925 
926  FileReader tempReader;
927  try {
928  tempReader = new FileReader(temps);
929  } catch (FileNotFoundException ex) {
930  logger.log(Level.SEVERE, "Error while trying to read the Autofill profiles json file for Firefox.", ex); //NON-NLS
931  this.addErrorMessage(
932  NbBundle.getMessage(this.getClass(), "Firefox.getAutofillProfiles.errMsg.errAnalyzeFile", this.getDisplayName(),
933  profileFile.getName()));
934  continue;
935  }
936 
937  JsonObject jsonRootObject;
938  JsonArray jAddressesArray;
939 
940  try {
941  jsonRootObject = JsonParser.parseReader(tempReader).getAsJsonObject();
942  jAddressesArray = jsonRootObject.getAsJsonArray("addresses"); //NON-NLS
943  } catch (JsonIOException | JsonSyntaxException | IllegalStateException ex) {
944  logger.log(Level.WARNING, "Error parsing Json for Firefox Autofill profiles.", ex); //NON-NLS
945  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Firefox.getAutofillProfiles.errMsg.errAnalyzingFile3",
946  this.getDisplayName(), profileFile.getName()));
947  continue;
948  }
949 
950  WebBrowserArtifactsHelper helper;
951  try {
952  // Helper to create web form address artifacts.
953  helper = new WebBrowserArtifactsHelper(
954  Case.getCurrentCaseThrows().getSleuthkitCase(),
955  NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName"),
956  profileFile,
957  ingestJobId
958  );
959  } catch (NoCurrentCaseException ex) {
960  logger.log(Level.SEVERE, "No case open, bailing.", ex); //NON-NLS
961  return;
962  }
963 
964  for (JsonElement result : jAddressesArray) {
965  JsonObject address = result.getAsJsonObject();
966  if (address == null) {
967  continue;
968  }
969 
970  JsonElement nameEl = address.get("name"); //NON-NLS
971  String name = (nameEl != null) ? nameEl.getAsString() : "";
972 
973  JsonElement emailEl = address.get("email"); //NON-NLS
974  String email = (emailEl != null) ? emailEl.getAsString() : "";
975 
976  JsonElement telEl = address.get("tel"); //NON-NLS
977  String tel = (telEl != null) ? telEl.getAsString() : "";
978  JsonElement telCountryCodeEl = address.get("tel-country-code"); //NON-NLS
979  String telCountryCode = (telCountryCodeEl != null) ? telCountryCodeEl.getAsString() : "";
980  JsonElement telNationalEl = address.get("tel-national"); //NON-NLS
981  String telNational = (telNationalEl != null) ? telNationalEl.getAsString() : "";
982 
983  String phoneNumber = makeTelNumber(tel, telCountryCode, telNational);
984 
985  JsonElement createdEl = address.get("timeCreated"); //NON-NLS
986  Long datetimeCreated = (createdEl != null) ? createdEl.getAsLong() / 1000 : Long.valueOf(0);
987  JsonElement lastusedEl = address.get("timeLastUsed"); //NON-NLS
988  Long datetimeLastUsed = (lastusedEl != null) ? lastusedEl.getAsLong() / 1000 : Long.valueOf(0);
989  JsonElement timesUsedEl = address.get("timesUsed"); //NON-NLS
990  Integer timesUsed = (timesUsedEl != null) ? timesUsedEl.getAsShort() : Integer.valueOf(0);
991 
992  JsonElement addressLine1El = address.get("address-line1"); //NON-NLS
993  String addressLine1 = (addressLine1El != null) ? addressLine1El.getAsString() : "";
994  JsonElement addressLine2El = address.get("address-line2"); //NON-NLS
995  String addressLine2 = (addressLine2El != null) ? addressLine2El.getAsString() : "";
996  JsonElement addressLine3El = address.get("address-line3"); //NON-NLS
997  String addressLine3 = (addressLine3El != null) ? addressLine3El.getAsString() : "";
998 
999  JsonElement postalCodeEl = address.get("postal-code"); //NON-NLS
1000  String postalCode = (postalCodeEl != null) ? postalCodeEl.getAsString() : "";
1001  JsonElement countryEl = address.get("country"); //NON-NLS
1002  String country = (countryEl != null) ? countryEl.getAsString() : "";
1003 
1004  String mailingAddress = makeFullAddress(addressLine1, addressLine2, addressLine3, postalCode, country);
1005 
1006  try {
1007  helper.addWebFormAddress(name, email, phoneNumber,
1008  mailingAddress, datetimeCreated, datetimeLastUsed, timesUsed);
1009  } catch (TskCoreException | Blackboard.BlackboardException ex) {
1010  logger.log(Level.SEVERE, "Error while trying to insert Firefox Autofill profile artifact{0}", ex); //NON-NLS
1011  this.addErrorMessage(
1012  NbBundle.getMessage(this.getClass(), "Firefox.getAutofillProfiles.errMsg.errAnalyzingFile4",
1013  this.getDisplayName(), profileFile.getName()));
1014  }
1015  }
1016  dbFile.delete();
1017  }
1018  }
1019 
1028  private String extractDomain(String url) {
1029  if (url == null || url.isEmpty()) {
1030  return url;
1031  }
1032 
1033  if (url.toLowerCase().startsWith(PLACE_URL_PREFIX)) {
1034  /*
1035  * Ignore URLs that begin with the matched text.
1036  */
1037  return null;
1038  }
1039 
1040  return NetworkUtils.extractDomain(url);
1041  }
1042 
1054  private String makeTelNumber(String tel, String telCountryCode, String telNational) {
1055 
1056  if (tel != null && !tel.isEmpty()) {
1057  return tel;
1058  }
1059 
1060  if ((telCountryCode != null && !telCountryCode.isEmpty())
1061  && (telNational != null && !telNational.isEmpty())) {
1062  return telCountryCode + telNational;
1063  }
1064 
1065  return "";
1066  }
1067 
1079  private String makeFullAddress(String addressLine1, String addressLine2, String addressLine3, String postalCode, String country) {
1080  String fullAddress = "";
1081  fullAddress = appendAddressField(fullAddress, addressLine1);
1082  fullAddress = appendAddressField(fullAddress, addressLine2);
1083  fullAddress = appendAddressField(fullAddress, addressLine3);
1084  fullAddress = appendAddressField(fullAddress, postalCode);
1085  fullAddress = appendAddressField(fullAddress, country);
1086 
1087  return fullAddress;
1088  }
1089 
1099  private String appendAddressField(String address, String addressfield) {
1100 
1101  String updatedAddress = address;
1102  if (addressfield != null && !addressfield.isEmpty()) {
1103  if (!updatedAddress.isEmpty()) {
1104  updatedAddress += ", ";
1105  }
1106  updatedAddress += addressfield;
1107  }
1108 
1109  return updatedAddress;
1110  }
1111 
1112 }

Copyright © 2012-2022 Basis Technology. Generated on: Tue Jun 27 2023
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.