]> WPIA git - gigi.git/blob - src/club/wpia/gigi/util/PublicSuffixes.java
401502f72f03df0d8aaf54d4bfd31cdb8ef47a93
[gigi.git] / src / club / wpia / gigi / util / PublicSuffixes.java
1 package club.wpia.gigi.util;
2
3 import java.io.BufferedReader;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.io.InputStreamReader;
7 import java.net.IDN;
8 import java.util.HashSet;
9
10 public class PublicSuffixes {
11
12     private HashSet<String> suffixes = new HashSet<>();
13
14     private HashSet<String> wildcards = new HashSet<>();
15
16     private HashSet<String> exceptions = new HashSet<>();
17
18     static final String url = "https://publicsuffix.org/list/effective_tld_names.dat";
19
20     private static PublicSuffixes instance;
21
22     private static PublicSuffixes generateDefault() throws IOException {
23         InputStream res = PublicSuffixes.class.getResourceAsStream("effective_tld_names.dat");
24
25         if (null == res) {
26             throw new Error("Public Suffix List could not be loaded.");
27         }
28
29         try (BufferedReader br = new BufferedReader(new InputStreamReader(res, "UTF-8"))) {
30             return new PublicSuffixes(br);
31         }
32     }
33
34     public synchronized static PublicSuffixes getInstance() {
35         if (instance == null) {
36             try {
37                 instance = generateDefault();
38             } catch (IOException e) {
39                 throw new Error(e);
40             }
41         }
42         return instance;
43     }
44
45     private PublicSuffixes(BufferedReader br) throws IOException {
46         String line;
47         while ((line = br.readLine()) != null) {
48             if (line.startsWith("//")) {
49                 continue;
50             }
51             if (line.isEmpty()) {
52                 continue;
53             }
54             String[] lineParts = line.split("\\s", 2);
55             if (lineParts.length == 0) {
56                 throw new Error("split had strange behavior");
57             }
58             line = lineParts[0];
59             if (line.startsWith("*.")) {
60                 String data = line.substring(2);
61                 if (data.contains("*") || data.contains("!")) {
62                     System.out.println("Error! unparsable public suffix line: " + line);
63                     continue;
64                 }
65                 addWildcard(IDN.toASCII(data));
66             } else if (line.startsWith("!")) {
67                 String data = line.substring(1);
68                 if (data.contains("*") || data.contains("!")) {
69                     System.out.println("Error! unparsable public suffix line: " + line);
70                     continue;
71                 }
72                 addException(IDN.toASCII(data));
73             } else {
74                 if (line.contains("*") || line.contains("!")) {
75                     System.out.println("Error! unparsable public suffix line: " + line);
76                     continue;
77                 }
78                 addSuffix(IDN.toASCII(line));
79             }
80         }
81     }
82
83     private void addWildcard(String data) {
84         wildcards.add(data);
85     }
86
87     private void addException(String data) {
88         exceptions.add(data);
89     }
90
91     private void addSuffix(String line) {
92         suffixes.add(line);
93     }
94
95     public String getRegistrablePart(String domain) {
96         if (domain == null) {
97             return null;
98         }
99         if (domain.startsWith(".")) {
100             return null;
101         }
102         if (isSuffix(domain) && !exceptions.contains(domain)) {
103             return null;
104         }
105         return getPublicSuffix0(domain);
106     }
107
108     private String getPublicSuffix0(String domain) {
109
110         int d = domain.indexOf('.');
111         if (d == -1) {
112             return null;
113         }
114         if (exceptions.contains(domain)) {
115             return domain;
116         }
117         String nextDomain = domain.substring(d + 1);
118         if (isSuffix(nextDomain)) {
119             return domain;
120         }
121
122         return getPublicSuffix0(nextDomain);
123     }
124
125     private boolean isSuffix(String domain) {
126         if (suffixes.contains(domain)) {
127             return true;
128         }
129         if (exceptions.contains(domain)) {
130             return false;
131         }
132         int idx = domain.indexOf('.');
133         if (idx != -1 && wildcards.contains(domain.substring(idx + 1))) {
134             return true;
135         }
136         return false;
137     }
138
139 }