Autopsy  4.16.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
CorrelationAttributeNormalizer.java
Go to the documentation of this file.
1 /*
2  *
3  * Autopsy Forensic Browser
4  *
5  * Copyright 2019 Basis Technology Corp.
6  * Contact: carrier <at> sleuthkit <dot> org
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 package org.sleuthkit.autopsy.centralrepository.datamodel;
21 
22 import java.util.Arrays;
23 import java.util.HashSet;
24 import java.util.List;
25 import java.util.Optional;
26 import java.util.Set;
27 import org.apache.commons.lang.StringUtils;
28 import org.apache.commons.validator.routines.DomainValidator;
29 import org.apache.commons.validator.routines.EmailValidator;
30 
35 final public class CorrelationAttributeNormalizer {
36 
37  //common seperators that may be removed for normalizing
38  private static final String SEPERATORS_REGEX = "[\\s-:]";
39 
49  public static String normalize(CorrelationAttributeInstance.Type attributeType, String data) throws CorrelationAttributeNormalizationException {
50 
51  if (attributeType == null) {
52  throw new CorrelationAttributeNormalizationException("Attribute type was null.");
53  }
54  if (data == null) {
55  throw new CorrelationAttributeNormalizationException("Correlation value was null.");
56  }
57 
58  String trimmedData = data.trim();
59 
60  switch (attributeType.getId()) {
62  return normalizeMd5(trimmedData);
64  return normalizeDomain(trimmedData);
66  return normalizeEmail(trimmedData);
68  return normalizePhone(trimmedData);
70  return normalizeUsbId(trimmedData);
72  return verifySsid(trimmedData);
74  return normalizeMac(trimmedData);
76  return normalizeImei(trimmedData);
78  return normalizeImsi(trimmedData);
80  return normalizeIccid(trimmedData);
81 
82  default:
83  try {
84  // If the atttribute is not one of the above
85  // but is one of the other default correlation types, then let the data go as is
87  for (CorrelationAttributeInstance.Type defaultCorrelationType : defaultCorrelationTypes) {
88  if (defaultCorrelationType.getId() == attributeType.getId()) {
89  return trimmedData;
90  }
91  }
92  final String errorMessage = String.format(
93  "Validator function not found for attribute type: %s",
94  attributeType.getDisplayName());
95  throw new CorrelationAttributeNormalizationException(errorMessage);
96  } catch (CentralRepoException ex) {
97  throw new CorrelationAttributeNormalizationException("Failed to get default correlation types.", ex);
98  }
99  }
100  }
101 
111  public static String normalize(int attributeTypeId, String data) throws CorrelationAttributeNormalizationException {
112  try {
114  Optional<CorrelationAttributeInstance.Type> typeOption = defaultTypes.stream().filter(attributeType -> attributeType.getId() == attributeTypeId).findAny();
115 
116  if (typeOption.isPresent()) {
117  CorrelationAttributeInstance.Type type = typeOption.get();
118  return CorrelationAttributeNormalizer.normalize(type, data);
119  } else {
120  throw new CorrelationAttributeNormalizationException(String.format("Given attributeTypeId did not correspond to any known Attribute: %s", attributeTypeId));
121  }
122  } catch (CentralRepoException ex) {
124  }
125  }
126 
130  private static String normalizeMd5(String data) throws CorrelationAttributeNormalizationException {
131  final String validMd5Regex = "^[a-f0-9]{32}$";
132  final String dataLowered = data.toLowerCase();
133  if (dataLowered.matches(validMd5Regex)) {
134  return dataLowered;
135  } else {
136  throw new CorrelationAttributeNormalizationException(String.format("Data purporting to be an MD5 was found not to comform to expected format: %s", data));
137  }
138  }
139 
144  private static String normalizeDomain(String data) throws CorrelationAttributeNormalizationException {
145  DomainValidator validator = DomainValidator.getInstance(true);
146  if (validator.isValid(data)) {
147  return data.toLowerCase();
148  } else {
149  final String validIpAddressRegex = "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$";
150  if (data.matches(validIpAddressRegex)) {
151  return data;
152  } else {
153  throw new CorrelationAttributeNormalizationException(String.format("Data was expected to be a valid domain: %s", data));
154  }
155  }
156  }
157 
167  static String normalizeEmail(String emailAddress) throws CorrelationAttributeNormalizationException {
168  if (isValidEmailAddress(emailAddress)) {
169  return emailAddress.toLowerCase().trim();
170  } else {
171  throw new CorrelationAttributeNormalizationException(String.format("Data was expected to be a valid email address: %s", emailAddress));
172  }
173  }
174 
184  static String normalizePhone(String phoneNumber) throws CorrelationAttributeNormalizationException {
185  if (isValidPhoneNumber(phoneNumber)) {
186  String normalizedNumber = phoneNumber.replaceAll("\\s+", ""); // remove spaces.
187  normalizedNumber = normalizedNumber.replaceAll("[\\-()]", ""); // remove parens & dashes.
188 
189  // ensure a min length
190  if (normalizedNumber.length() < MIN_PHONENUMBER_LEN) {
191  throw new CorrelationAttributeNormalizationException(String.format("Phone number string %s is too short ", phoneNumber));
192  }
193  return normalizedNumber;
194 
195  } else {
196  throw new CorrelationAttributeNormalizationException(String.format("Data was expected to be a valid phone number: %s", phoneNumber));
197  }
198  }
199 
203  private static String normalizeUsbId(String data) throws CorrelationAttributeNormalizationException {
204  //TODO replace with correct usb id validation at a later date
205  return data;
206  }
207 
221  private static String verifySsid(String data) throws CorrelationAttributeNormalizationException {
222  if (data.length() <= 32) {
223  return data;
224  } else {
225  throw new CorrelationAttributeNormalizationException("Name provided was longer than the maximum valid SSID (32 characters). Name: " + data);
226  }
227  }
228 
251  private static String normalizeIccid(String data) throws CorrelationAttributeNormalizationException {
252  final String validIccidRegex = "^89[f0-9]{17,22}$";
253  final String iccidWithoutSeperators = data.toLowerCase().replaceAll(SEPERATORS_REGEX, "");
254  if (iccidWithoutSeperators.matches(validIccidRegex)) {
255  return iccidWithoutSeperators;
256  } else {
257  throw new CorrelationAttributeNormalizationException("Data provided was not a valid ICCID. : " + data);
258  }
259  }
260 
278  private static String normalizeImsi(String data) throws CorrelationAttributeNormalizationException {
279  final String validImsiRegex = "^[0-9]{14,15}$";
280  final String imsiWithoutSeperators = data.replaceAll(SEPERATORS_REGEX, "");
281  if (imsiWithoutSeperators.matches(validImsiRegex)) {
282  return imsiWithoutSeperators;
283  } else {
284  throw new CorrelationAttributeNormalizationException("Data provided was not a valid Imsi. : " + data);
285  }
286  }
287 
302  private static String normalizeMac(String data) throws CorrelationAttributeNormalizationException {
303  final String validMacRegex = "^([a-f0-9]{12}|[a-f0-9]{16})$";
304  final String macWithoutSeperators = data.toLowerCase().replaceAll(SEPERATORS_REGEX, "");
305  if (macWithoutSeperators.matches(validMacRegex)) {
306  return macWithoutSeperators;
307  } else {
308  throw new CorrelationAttributeNormalizationException("Data provided was not a valid Imsi. : " + data);
309  }
310  }
311 
331  private static String normalizeImei(String data) throws CorrelationAttributeNormalizationException {
332  final String validImeiRegex = "^[0-9]{14,16}$";
333  final String imeiWithoutSeperators = data.replaceAll(SEPERATORS_REGEX, "");
334  if (imeiWithoutSeperators.matches(validImeiRegex)) {
335  return imeiWithoutSeperators;
336  } else {
337  throw new CorrelationAttributeNormalizationException("Data provided was not a valid Imsi. : " + data);
338  }
339  }
340 
341  // These symbols are allowed in written form of phone numbers.
342  // A '+' is allowed only as a leading digit and hence not inlcuded here.
343  // While a dialed sequence may have additonal special characters, such as #, * or ',',
344  // CR attributes represent accounts and hence those chatracter are not allowed.
345  private static final Set<String> PHONENUMBER_CHARS = new HashSet<>(Arrays.asList(
346  "-", "(", ")"
347  ));
348 
349  private static final int MIN_PHONENUMBER_LEN = 5;
350 
359  static boolean isValidPhoneNumber(String phoneNumber) {
360 
361  // A phone number may have a leading '+', special telephony chars, or digits.
362  // Anything else implies an invalid phone number.
363  for (int i = 0; i < phoneNumber.length(); i++) {
364  if ( !((i == 0 && phoneNumber.charAt(i) == '+')
365  || Character.isSpaceChar(phoneNumber.charAt(i))
366  || Character.isDigit(phoneNumber.charAt(i))
367  || PHONENUMBER_CHARS.contains(String.valueOf(phoneNumber.charAt(i))))) {
368  return false;
369  }
370  }
371 
372  // ensure a min length
373  return phoneNumber.length() >= MIN_PHONENUMBER_LEN;
374  }
375 
384  static boolean isValidEmailAddress(String emailAddress) {
385  if (!StringUtils.isEmpty(emailAddress)) {
386  EmailValidator validator = EmailValidator.getInstance(true, true);
387  return validator.isValid(emailAddress);
388  }
389 
390  return false;
391  }
392 
397  //Empty constructor
398  }
399 }
static String normalize(CorrelationAttributeInstance.Type attributeType, String data)

Copyright © 2012-2020 Basis Technology. Generated on: Tue Sep 22 2020
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.