274 lines
7.8 KiB
Java
274 lines
7.8 KiB
Java
/*
|
|
* Copyright (C) 2021 Christian Pierre MOMON <christian@momon.org>
|
|
*
|
|
* This file is part of Logar, simple tool to manage http log files.
|
|
*
|
|
* Logar is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* Logar is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with Logar. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
package fr.devinsy.logar.app.anonymizer;
|
|
|
|
import java.io.File;
|
|
import java.io.FileOutputStream;
|
|
import java.io.IOException;
|
|
import java.io.PrintWriter;
|
|
import java.time.format.DateTimeParseException;
|
|
import java.util.regex.Matcher;
|
|
import java.util.regex.Pattern;
|
|
import java.util.zip.GZIPOutputStream;
|
|
|
|
import org.apache.commons.io.IOUtils;
|
|
import org.apache.commons.lang3.StringUtils;
|
|
import org.april.logar.util.LineIterator;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
import fr.devinsy.logar.app.log.Log;
|
|
import fr.devinsy.logar.app.log.LogParser;
|
|
|
|
/**
|
|
* The Class Anonymizer.
|
|
*/
|
|
/**
|
|
* @author cpm
|
|
*
|
|
*/
|
|
public final class Anonymizer
|
|
{
|
|
private static Logger logger = LoggerFactory.getLogger(Anonymizer.class);
|
|
|
|
public static final Pattern IPV4_PATTERN = Pattern.compile("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}");
|
|
public static final Pattern IPV6_PATTERN = Pattern.compile("([0-9a-f]){1,4}(:{1,2}[0-9a-f]{0,4}){4,7}", Pattern.CASE_INSENSITIVE);
|
|
|
|
private AnonMap map;
|
|
|
|
/**
|
|
* Instantiates a new anonymizer.
|
|
*/
|
|
public Anonymizer()
|
|
{
|
|
this.map = new AnonMap();
|
|
}
|
|
|
|
/**
|
|
* Anonymize.
|
|
*
|
|
* @param source
|
|
* the source
|
|
*/
|
|
public void anonymize(final File source)
|
|
{
|
|
if (source == null)
|
|
{
|
|
throw new IllegalArgumentException("Null parameter.");
|
|
}
|
|
else if (!source.isFile())
|
|
{
|
|
throw new IllegalArgumentException("Parameter is not a file.");
|
|
}
|
|
else if (!StringUtils.containsAny(source.getName(), "access", "error"))
|
|
{
|
|
throw new IllegalArgumentException("File name does not contain 'access' or 'error'.");
|
|
}
|
|
else
|
|
{
|
|
System.out.println("== Anonymize log for [" + source.getName() + "]");
|
|
boolean isAccessFile = source.getName().contains("access");
|
|
|
|
File target;
|
|
if (source.getName().endsWith(".log.gz"))
|
|
{
|
|
target = new File(source.getParentFile(), source.getName().replace(".log.gz", "-anon.log.gz"));
|
|
}
|
|
else
|
|
{
|
|
target = new File(source.getParentFile(), source.getName().replace(".log", "-anon.log"));
|
|
}
|
|
|
|
PrintWriter out = null;
|
|
try
|
|
{
|
|
LineIterator iterator = new LineIterator(source);
|
|
out = new PrintWriter(new GZIPOutputStream(new FileOutputStream(target)));
|
|
while (iterator.hasNext())
|
|
{
|
|
String line = iterator.next();
|
|
|
|
try
|
|
{
|
|
Log anon;
|
|
if (isAccessFile)
|
|
{
|
|
Log log = LogParser.parseAccessLog(line);
|
|
// logger.info("line={}", line);
|
|
// logger.info("log =[{}][{}][{}]", log.getIp(),
|
|
// log.getUser(), log.getDatetime());
|
|
|
|
anon = anonymizeAccess(log);
|
|
// logger.info("anon=[{}][{}][{}]", anon.getIp(),
|
|
// anon.getUser(), anon.getDatetime());
|
|
// logger.info("anon={}", anon);
|
|
|
|
// Make a check.
|
|
if (StringUtils.equals(line, anon.getLine()))
|
|
{
|
|
System.err.println("Anonymize failed detected: " + line);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Log log = LogParser.parseErrorLog(line);
|
|
|
|
anon = anonymizeError(log);
|
|
}
|
|
|
|
out.println(anon);
|
|
}
|
|
catch (IllegalArgumentException exception)
|
|
{
|
|
System.out.println("Bad format line: " + line);
|
|
exception.printStackTrace();
|
|
}
|
|
catch (DateTimeParseException exception)
|
|
{
|
|
System.out.println("Bad datetime format: " + line);
|
|
}
|
|
}
|
|
}
|
|
catch (IOException exception)
|
|
{
|
|
System.err.println("Error with file [" + source.getAbsolutePath() + "]");
|
|
exception.printStackTrace();
|
|
}
|
|
finally
|
|
{
|
|
IOUtils.closeQuietly(out);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Anonymize.
|
|
*
|
|
* @param log
|
|
* the log
|
|
* @return the log
|
|
*/
|
|
public Log anonymizeAccess(final Log log)
|
|
{
|
|
Log result;
|
|
|
|
//
|
|
String anonIp = this.map.anonymizeIp(log.getIp());
|
|
String line = log.getLine().replace(log.getIp(), anonIp);
|
|
|
|
//
|
|
if (!StringUtils.equals(log.getUser(), "-"))
|
|
{
|
|
String anonUser = this.map.anonymizeUser(log.getUser());
|
|
line = line.replaceFirst(" " + log.getUser(), " " + anonUser);
|
|
}
|
|
|
|
//
|
|
result = new Log(line, log.getDatetime());
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Anonymize error.
|
|
*
|
|
* @param log
|
|
* the log
|
|
* @return the log
|
|
*/
|
|
public Log anonymizeError(final Log log)
|
|
{
|
|
Log result;
|
|
|
|
// Search and anonymized Ipv4 addresses.
|
|
Matcher matcher = IPV4_PATTERN.matcher(log.getLine());
|
|
String anonLine = log.getLine();
|
|
while (matcher.find())
|
|
{
|
|
String left = anonLine.substring(0, matcher.start());
|
|
String ipv4 = matcher.group();
|
|
String right = anonLine.substring(matcher.end());
|
|
|
|
String anonIpv4 = this.map.anonymizeIp(ipv4);
|
|
anonLine = left + anonIpv4 + right;
|
|
}
|
|
|
|
// Search and anonymized Ipv4 addresses.
|
|
matcher = IPV6_PATTERN.matcher(anonLine);
|
|
while (matcher.find())
|
|
{
|
|
String left = anonLine.substring(0, matcher.start());
|
|
String ipv6 = matcher.group();
|
|
String right = anonLine.substring(matcher.end());
|
|
|
|
String anonIpv6 = this.map.anonymizeIp(ipv6);
|
|
anonLine = left + anonIpv6 + right;
|
|
}
|
|
|
|
result = new Log(anonLine, log.getDatetime());
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Gets the map table.
|
|
*
|
|
* @return the map table
|
|
*/
|
|
public AnonMap getMapTable()
|
|
{
|
|
AnonMap result;
|
|
|
|
result = this.map;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Inits the map.
|
|
*
|
|
* @param source
|
|
* the source
|
|
*/
|
|
public void loadMapTable(final File source)
|
|
{
|
|
if (source != null)
|
|
{
|
|
this.map.addAll(AnonMapFile.load(source));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Save map table.
|
|
*
|
|
* @param target
|
|
* the target
|
|
*/
|
|
public void SaveMapTable(final File target)
|
|
{
|
|
if (target != null)
|
|
{
|
|
AnonMapFile.save(target, this.map);
|
|
}
|
|
}
|
|
}
|