Skip to content

Commit

Permalink
Revert Certificate
Browse files Browse the repository at this point in the history
  • Loading branch information
Vzor- committed Sep 12, 2024
1 parent e8f8e0c commit 64bd7d8
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 112 deletions.
126 changes: 26 additions & 100 deletions src/qz/auth/Certificate.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@
import java.nio.file.Path;
import java.security.*;
import java.security.cert.*;
import java.time.*;
import java.time.DateTimeException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;

Expand All @@ -32,7 +35,6 @@ public class Certificate {

private static final Logger log = LogManager.getLogger(Certificate.class);
private static final String QUIETLY_FAIL = "quiet";
private static final String NOT_PROVIDED = "Not Provided";

public enum Algorithm {
SHA1("SHA1withRSA"),
Expand All @@ -46,39 +48,6 @@ public enum Algorithm {
}
}

public enum Field {
ORGANIZATION("Organization"),
COMMON_NAME("Common Name"),
TRUSTED("Trusted"),
VALID_FROM("Valid From"),
VALID_TO("Valid To"),
FINGERPRINT("Fingerprint"),
VALID("Valid");

String description;

// List of fields needed to construct a new cert.
public static final Field[] saveFields = new Field[] {FINGERPRINT, COMMON_NAME, ORGANIZATION, VALID_FROM, VALID_TO, VALID};
public static final Field[] displayFields = new Field[] {ORGANIZATION, COMMON_NAME, TRUSTED, VALID_FROM, VALID_TO, FINGERPRINT};

Field(String description) {
this.description = description;
}

@Override
public String toString() {
return description;
}

public String getDescription() {
return description;
}

public static int size() {
return values().length;
}
}

public static ArrayList<Certificate> rootCAs = new ArrayList<>();
public static Certificate builtIn;
private static CertPathValidator validator;
Expand All @@ -87,12 +56,15 @@ public static int size() {
// id-at-description used for storing renewal information
private static ASN1ObjectIdentifier RENEWAL_OF = new ASN1ObjectIdentifier("2.5.4.13");

public static final String[] saveFields = new String[] {"fingerprint", "commonName", "organization", "validFrom", "validTo", "valid"};

public static final String SPONSORED_CN_PREFIX = "Sponsored:";

// Valid date range allows UI to only show "Expired" text for valid certificates
private static final Instant UNKNOWN_MIN = LocalDateTime.MIN.toInstant(ZoneOffset.UTC);
private static final Instant UNKNOWN_MAX = LocalDateTime.MAX.toInstant(ZoneOffset.UTC);

// This `dateFormat` corresponds to the `dateParse` in CertificateTable. If this line is changed, change it there as well.
private static DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
private static DateTimeFormatter dateParse = DateTimeFormatter.ofPattern("uuuu-MM-dd['T'][ ]HH:mm:ss[.n]['Z']"); //allow parsing of both ISO and custom formatted dates

Expand All @@ -114,13 +86,13 @@ public static int size() {
public static final Certificate UNKNOWN;

static {
HashMap<Field,String> map = new HashMap<>();
map.put(Field.FINGERPRINT, "UNKNOWN REQUEST");
map.put(Field.COMMON_NAME, "An anonymous request");
map.put(Field.ORGANIZATION, "Unknown");
map.put(Field.VALID_FROM, UNKNOWN_MIN.toString());
map.put(Field.VALID_TO, UNKNOWN_MAX.toString());
map.put(Field.VALID, "false");
HashMap<String,String> map = new HashMap<>();
map.put("fingerprint", "UNKNOWN REQUEST");
map.put("commonName", "An anonymous request");
map.put("organization", "Unknown");
map.put("validFrom", UNKNOWN_MIN.toString());
map.put("validTo", UNKNOWN_MAX.toString());
map.put("valid", "false");
UNKNOWN = Certificate.loadCertificate(map);
}

Expand Down Expand Up @@ -344,16 +316,16 @@ private Certificate() {}
/**
* Used to rebuild a certificate for the 'Saved Sites' screen without having to decrypt the certificates again
*/
public static Certificate loadCertificate(HashMap<Field,String> data) {
public static Certificate loadCertificate(HashMap<String,String> data) {
Certificate cert = new Certificate();

cert.fingerprint = data.get(Field.FINGERPRINT);
cert.commonName = data.get(Field.COMMON_NAME);
cert.organization = data.get(Field.ORGANIZATION);
cert.fingerprint = data.get("fingerprint");
cert.commonName = data.get("commonName");
cert.organization = data.get("organization");

try {
cert.validFrom = Instant.from(LocalDateTime.from(dateParse.parse(data.get(Field.VALID_FROM))).atZone(ZoneOffset.UTC));
cert.validTo = Instant.from(LocalDateTime.from(dateParse.parse(data.get(Field.VALID_TO))).atZone(ZoneOffset.UTC));
cert.validFrom = Instant.from(LocalDateTime.from(dateParse.parse(data.get("validFrom"))).atZone(ZoneOffset.UTC));
cert.validTo = Instant.from(LocalDateTime.from(dateParse.parse(data.get("validTo"))).atZone(ZoneOffset.UTC));
}
catch(DateTimeException e) {
cert.validFrom = UNKNOWN_MIN;
Expand All @@ -362,7 +334,7 @@ public static Certificate loadCertificate(HashMap<Field,String> data) {
log.warn("Unable to parse certificate date: {}", e.getMessage());
}

cert.valid = Boolean.parseBoolean(data.get(Field.VALID));
cert.valid = Boolean.parseBoolean(data.get("valid"));

return cert;
}
Expand Down Expand Up @@ -434,30 +406,6 @@ private static boolean existsInAnyFile(String fingerprint, File... files) {
return false;
}

public String get(Field field) {
return get(field, null);
}

public String get(Field field, Object optArg) {
switch(field) {
case ORGANIZATION:
return getOrganization();
case COMMON_NAME:
return getCommonName();
case TRUSTED:
return String.valueOf(isTrusted());
case VALID_FROM:
return getValidFrom((TimeZone)optArg);
case VALID_TO:
return getValidTo((TimeZone)optArg);
case FINGERPRINT:
return getFingerprint();
case VALID:
return String.valueOf(isValid());
default:
return null;
}
}

public String getFingerprint() {
return fingerprint;
Expand All @@ -472,41 +420,19 @@ public String getOrganization() {
}

public String getValidFrom() {
return getValidFrom(null);
}

public String getValidFrom(TimeZone timeZone) {
if (validFrom.isAfter(UNKNOWN_MIN)) {
return formatDate(validFrom, timeZone);
return dateFormat.format(validFrom.atZone(ZoneOffset.UTC));
} else {
return NOT_PROVIDED;
return "Not Provided";
}
}

public String getValidTo() {
return getValidTo(null);
}

public String getValidTo(TimeZone timeZone) {
if (validTo.isBefore(UNKNOWN_MAX)) {
return formatDate(validTo, timeZone);
} else {
return NOT_PROVIDED;
}
}

private static String formatDate(Instant date, TimeZone timeZone) {
ZoneId zoneId;
String timeZoneString;
if (timeZone == null) {
zoneId = ZoneOffset.UTC;
timeZoneString = ""; // If no timezone was included, don't append a timezone ID.
return dateFormat.format(validTo.atZone(ZoneOffset.UTC));
} else {
zoneId = timeZone.toZoneId();
timeZoneString = " " + timeZone.getDisplayName(false, TimeZone.SHORT);
return "Not Provided";
}

return dateFormat.format(date.atZone(zoneId)) + timeZoneString;
}

public Instant getValidFromDate() {
Expand Down Expand Up @@ -609,4 +535,4 @@ private static String getSubjectX509Principal(X509Certificate cert, ASN1ObjectId
return "";
}

}
}
6 changes: 3 additions & 3 deletions src/qz/ui/SiteManagerDialog.java
Original file line number Diff line number Diff line change
Expand Up @@ -554,10 +554,10 @@ public ArrayList<CertificateDisplay> readCertificates(ArrayList<CertificateDispl
if (line.startsWith("#")) { continue; } //treat these lines as comments
String[] data = line.split("\\t");

if (data.length == Certificate.Field.saveFields.length) {
HashMap<Certificate.Field,String> dataMap = new HashMap<>();
if (data.length == Certificate.saveFields.length) {
HashMap<String, String> dataMap = new HashMap<>();
for(int i = 0; i < data.length; i++) {
dataMap.put(Certificate.Field.saveFields[i], data[i]);
dataMap.put(Certificate.saveFields[i], data[i]);
}

CertificateDisplay certificate = new CertificateDisplay(Certificate.loadCertificate(dataMap), local);
Expand Down
70 changes: 61 additions & 9 deletions src/qz/ui/component/CertificateTable.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,14 @@
import java.awt.*;
import java.awt.event.*;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAccessor;
import java.util.TimeZone;
import java.util.function.Function;

/**
* Created by Tres on 2/22/2015.
Expand All @@ -20,13 +26,59 @@ public class CertificateTable extends DisplayTable implements Themeable {
private Certificate cert;

private static final TimeZone UTC_TIME_ZONE = TimeZone.getTimeZone("UTC");
private static DateTimeFormatter dateParse = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

private Instant warn;
private Instant now;
private boolean useLocalTimezoneValidTo = false;
private boolean useLocalTimezoneValidFrom = false;

enum CertificateField {
ORGANIZATION("Organization", (Certificate cert) -> cert.getOrganization()),
COMMON_NAME("Common Name", (Certificate cert) -> cert.getCommonName()),
TRUSTED("Trusted", (Certificate cert) -> cert.isTrusted()),
VALID_FROM("Valid From", (Certificate cert) -> cert.getValidFrom()),
VALID_TO("Valid To", (Certificate cert) -> cert.getValidTo()),
FINGERPRINT("Fingerprint", (Certificate cert) -> cert.getFingerprint());

String description;
Function<Certificate, Object> getter;

CertificateField(String description, Function<Certificate, Object> getter) {
this.description = description;
this.getter = getter;
}

public String getValue(Certificate cert, TimeZone timeZone) {
switch(this) {
case VALID_FROM:
case VALID_TO:
TemporalAccessor parsedDate = dateParse.parse(getter.apply(cert).toString()); // parse date string from cert
ZonedDateTime utcTime = LocalDateTime.from(parsedDate).atZone(ZoneOffset.UTC); // shift the timezone
return dateParse.format(Instant.from(utcTime).atZone(timeZone.toZoneId())) + " " + timeZone.getDisplayName(false, TimeZone.SHORT);
default:
return getter.apply(cert).toString();
}
}

@Override
public String toString() {
return description;
}

public String getDescription() {
return description;
}

public static int size() {
return values().length;
}
}

public CertificateTable(IconCache iconCache) {
super(iconCache);


setDefaultRenderer(Object.class, new CertificateTableCellRenderer());
addMouseListener(new MouseAdapter() {
int lastRow = -1;
Expand All @@ -40,12 +92,12 @@ public void mousePressed(MouseEvent e) {
int col = target.getSelectedColumn();
// Only trigger after the cell is click AND highlighted. This make copying text easier.
if (row == lastRow && col == lastCol) {
Certificate.Field rowKey = (Certificate.Field)target.getValueAt(row, 0);
if (rowKey == Certificate.Field.VALID_TO) {
CertificateField rowKey = (CertificateField)target.getValueAt(row, 0);
if (rowKey == CertificateField.VALID_TO) {
useLocalTimezoneValidTo = !useLocalTimezoneValidTo;
refreshComponents();
changeSelection(row, col, false, false);
} else if (rowKey == Certificate.Field.VALID_FROM) {
} else if (rowKey == CertificateField.VALID_FROM) {
useLocalTimezoneValidFrom = !useLocalTimezoneValidFrom;
refreshComponents();
changeSelection(row, col, false, false);
Expand Down Expand Up @@ -80,7 +132,7 @@ public void refreshComponents() {
removeRows();

// First Column
for(Certificate.Field field : Certificate.Field.displayFields) {
for(CertificateField field : CertificateField.values()) {
TimeZone timeZone = null;
switch(field){
case TRUSTED:
Expand All @@ -95,7 +147,7 @@ public void refreshComponents() {
default:
break;
}
model.addRow(new Object[] {field, cert.get(field, timeZone)});
model.addRow(new Object[] {field, field.getValue(cert, timeZone)});
}

repaint();
Expand All @@ -108,7 +160,7 @@ public void refresh() {
}

public void autoSize() {
super.autoSize(Certificate.Field.displayFields.length, 2);
super.autoSize(CertificateField.size(), 2);
}

/** Custom cell renderer for JTable to allow colors and styles not directly available in a JTable */
Expand All @@ -119,8 +171,8 @@ public Component getTableCellRendererComponent(JTable table, Object value, boole
JLabel label = (JLabel)super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);

// First Column
if (value instanceof Certificate.Field) {
switch((Certificate.Field)value) {
if (value instanceof CertificateField) {
switch((CertificateField)value) {
case VALID_FROM:
boolean futureExpiration = cert.getValidFromDate().isAfter(now);
label = stylizeLabel(futureExpiration? STATUS_WARNING:STATUS_NORMAL, label, isSelected, "future inception");
Expand All @@ -145,7 +197,7 @@ public Component getTableCellRendererComponent(JTable table, Object value, boole
// Second Column
if (cert == null || col < 1) { return stylizeLabel(STATUS_NORMAL, label, isSelected); }

Certificate.Field field = (Certificate.Field)table.getValueAt(row, col - 1);
CertificateField field = (CertificateField)table.getValueAt(row, col - 1);
if (field == null) { return stylizeLabel(STATUS_NORMAL, label, isSelected); }
switch(field) {
case TRUSTED:
Expand Down

0 comments on commit 64bd7d8

Please sign in to comment.