Autopsy 4.22.1
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 */
20package org.sleuthkit.autopsy.centralrepository.datamodel;
21
22import java.util.Arrays;
23import java.util.HashSet;
24import java.util.List;
25import java.util.Optional;
26import java.util.Set;
27import org.apache.commons.lang.StringUtils;
28import org.apache.commons.validator.routines.DomainValidator;
29import org.apache.commons.validator.routines.EmailValidator;
30import org.sleuthkit.autopsy.coreutils.NetworkUtils;
31
37
38 //common seperators that may be removed for normalizing
39 private static final String SEPERATORS_REGEX = "[\\s-:]";
40
51
52 if (attributeType == null) {
53 throw new CentralRepoException("Attribute type was null.");
54 }
55 if (data == null) {
56 throw new CentralRepoException("Correlation value was null.");
57 }
58
59 String trimmedData = data.trim();
60
61 switch (attributeType.getId()) {
63 return normalizeMd5(trimmedData);
65 return normalizeDomain(trimmedData);
67 return normalizeEmail(trimmedData);
69 return normalizePhone(trimmedData);
71 return normalizeUsbId(trimmedData);
73 return verifySsid(trimmedData);
75 return normalizeMac(trimmedData);
77 return normalizeImei(trimmedData);
79 return normalizeImsi(trimmedData);
81 return normalizeIccid(trimmedData);
82
83 default:
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 CentralRepoException(errorMessage);
96 }
97 }
98
108 public static String normalize(int attributeTypeId, String data) throws CorrelationAttributeNormalizationException, CentralRepoException {
110 Optional<CorrelationAttributeInstance.Type> typeOption = defaultTypes.stream().filter(attributeType -> attributeType.getId() == attributeTypeId).findAny();
111
112 if (typeOption.isPresent()) {
113 CorrelationAttributeInstance.Type type = typeOption.get();
114 return CorrelationAttributeNormalizer.normalize(type, data);
115 } else {
116 throw new CentralRepoException(String.format("Given attributeTypeId did not correspond to any known Attribute: %s", attributeTypeId));
117 }
118 }
119
123 private static String normalizeMd5(String data) throws CorrelationAttributeNormalizationException {
124 final String validMd5Regex = "^[a-f0-9]{32}$";
125 final String dataLowered = data.toLowerCase();
126 if (dataLowered.matches(validMd5Regex)) {
127 return dataLowered;
128 } else {
129 throw new CorrelationAttributeNormalizationException(String.format("Data purporting to be an MD5 was found not to comform to expected format: %s", data));
130 }
131 }
132
137 private static String normalizeDomain(String data) throws CorrelationAttributeNormalizationException {
138 DomainValidator validator = DomainValidator.getInstance(true);
139 if (validator.isValid(data)) {
140 return NetworkUtils.extractDomain(data.toLowerCase());
141 } else {
142 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])$";
143 if (data.matches(validIpAddressRegex)) {
144 return NetworkUtils.extractDomain(data);
145 } else {
146 throw new CorrelationAttributeNormalizationException(String.format("Data was expected to be a valid domain: %s", data));
147 }
148 }
149 }
150
160 static String normalizeEmail(String emailAddress) throws CorrelationAttributeNormalizationException {
161 if (isValidEmailAddress(emailAddress)) {
162 return emailAddress.toLowerCase().trim();
163 } else {
164 throw new CorrelationAttributeNormalizationException(String.format("Data was expected to be a valid email address: %s", emailAddress));
165 }
166 }
167
177 static String normalizePhone(String phoneNumber) throws CorrelationAttributeNormalizationException {
178 if (isValidPhoneNumber(phoneNumber)) {
179 String normalizedNumber = phoneNumber.replaceAll("\\s+", ""); // remove spaces.
180 normalizedNumber = normalizedNumber.replaceAll("[\\-()]", ""); // remove parens & dashes.
181
182 // ensure a min length
183 if (normalizedNumber.length() < MIN_PHONENUMBER_LEN) {
184 throw new CorrelationAttributeNormalizationException(String.format("Phone number string %s is too short ", phoneNumber));
185 }
186 return normalizedNumber;
187
188 } else {
189 throw new CorrelationAttributeNormalizationException(String.format("Data was expected to be a valid phone number: %s", phoneNumber));
190 }
191 }
192
196 private static String normalizeUsbId(String data) throws CorrelationAttributeNormalizationException {
197 //TODO replace with correct usb id validation at a later date
198 return data;
199 }
200
214 private static String verifySsid(String data) throws CorrelationAttributeNormalizationException {
215 if (data.length() <= 32) {
216 return data;
217 } else {
218 throw new CorrelationAttributeNormalizationException("Name provided was longer than the maximum valid SSID (32 characters). Name: " + data);
219 }
220 }
221
244 private static String normalizeIccid(String data) throws CorrelationAttributeNormalizationException {
245 final String validIccidRegex = "^89[f0-9]{17,22}$";
246 final String iccidWithoutSeperators = data.toLowerCase().replaceAll(SEPERATORS_REGEX, "");
247 if (iccidWithoutSeperators.matches(validIccidRegex)) {
248 return iccidWithoutSeperators;
249 } else {
250 throw new CorrelationAttributeNormalizationException("Data provided was not a valid ICCID. : " + data);
251 }
252 }
253
271 private static String normalizeImsi(String data) throws CorrelationAttributeNormalizationException {
272 final String validImsiRegex = "^[0-9]{14,15}$";
273 final String imsiWithoutSeperators = data.replaceAll(SEPERATORS_REGEX, "");
274 if (imsiWithoutSeperators.matches(validImsiRegex)) {
275 return imsiWithoutSeperators;
276 } else {
277 throw new CorrelationAttributeNormalizationException("Data provided was not a valid IMSI. : " + data);
278 }
279 }
280
295 private static String normalizeMac(String data) throws CorrelationAttributeNormalizationException {
296 final String validMacRegex = "^([a-f0-9]{12}|[a-f0-9]{16})$";
297 final String macWithoutSeperators = data.toLowerCase().replaceAll(SEPERATORS_REGEX, "");
298 if (macWithoutSeperators.matches(validMacRegex)) {
299 return macWithoutSeperators;
300 } else {
301 throw new CorrelationAttributeNormalizationException("Data provided was not a valid MAC address. : " + data);
302 }
303 }
304
324 private static String normalizeImei(String data) throws CorrelationAttributeNormalizationException {
325 final String validImeiRegex = "^[0-9]{14,16}$";
326 final String imeiWithoutSeperators = data.replaceAll(SEPERATORS_REGEX, "");
327 if (imeiWithoutSeperators.matches(validImeiRegex)) {
328 return imeiWithoutSeperators;
329 } else {
330 throw new CorrelationAttributeNormalizationException("Data provided was not a valid IMEI. : " + data);
331 }
332 }
333
334 // These symbols are allowed in written form of phone numbers.
335 // A '+' is allowed only as a leading digit and hence not inlcuded here.
336 // While a dialed sequence may have additonal special characters, such as #, * or ',',
337 // CR attributes represent accounts and hence those chatracter are not allowed.
338 private static final Set<String> PHONENUMBER_CHARS = new HashSet<>(Arrays.asList(
339 "-", "(", ")"
340 ));
341
342 private static final int MIN_PHONENUMBER_LEN = 5;
343
352 static boolean isValidPhoneNumber(String phoneNumber) {
353
354 // A phone number may have a leading '+', special telephony chars, or digits.
355 // Anything else implies an invalid phone number.
356 for (int i = 0; i < phoneNumber.length(); i++) {
357 if ( !((i == 0 && phoneNumber.charAt(i) == '+')
358 || Character.isSpaceChar(phoneNumber.charAt(i))
359 || Character.isDigit(phoneNumber.charAt(i))
360 || PHONENUMBER_CHARS.contains(String.valueOf(phoneNumber.charAt(i))))) {
361 return false;
362 }
363 }
364
365 // ensure a min length
366 return phoneNumber.length() >= MIN_PHONENUMBER_LEN;
367 }
368
377 static boolean isValidEmailAddress(String emailAddress) {
378 if (!StringUtils.isEmpty(emailAddress)) {
379 EmailValidator validator = EmailValidator.getInstance(true, true);
380 return validator.isValid(emailAddress);
381 }
382
383 return false;
384 }
385
390 //Empty constructor
391 }
392}
static String normalize(CorrelationAttributeInstance.Type attributeType, String data)
static String extractDomain(String urlString)

Copyright © 2012-2024 Sleuth Kit Labs. Generated on:
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.