· 6 years ago · Aug 13, 2019, 10:26 PM
1package pine;
2
3import java.time.Year;
4import java.util.Arrays;
5import java.util.Calendar;
6import java.util.HashSet;
7import java.util.Map.Entry;
8import java.util.NavigableMap;
9import java.util.Set;
10import java.util.TreeMap;
11
12import javax.crypto.KeyGenerator;
13import javax.crypto.SecretKey;
14
15/**
16 * Generates the String text necessary to generate pinescript code for trial and member secret keys.
17 */
18public class PineKeygen {
19
20 /** Default time zone. */
21 private static final String defaultTZ = "America/New_York";
22
23 /**
24 * Key: Integer order of the key<br>
25 * Value: The key
26 */
27 private static NavigableMap<Integer, String> trialKeys = new TreeMap<>((k1, k2) -> {
28 return Integer.compare(k1, k2);
29 });
30
31 /**
32 * Key: Integer order of the key<br>
33 * Value: The key
34 */
35 private static NavigableMap<Integer, String> subKeys = new TreeMap<>((k1, k2) -> {
36 return Integer.compare(k1, k2);
37 });
38
39 /** Calendar. */
40 private static Calendar calendar = Calendar.getInstance();
41
42 /**
43 * @param args Syntax: validVarName:String numMembers:int everyXWeeks:int timeZone:String endHour:int
44 * endMinute:int
45 * <p>
46 * <i>validVarName</i> will have a boolean <tt>true</tt> or <tt>false</tt> if the tested key is
47 * currently valid. A valid key is <tt>true</tt> only if the time stamp associated with that
48 * key (if it exists) has not yet expired for a trial, or it is an active subscription key
49 * (required).
50 * <p>
51 * <i>numMembers</i> is an integer that designates the total number of active member keys to
52 * generate (required)
53 * <p>
54 * <i>everyXDays</i> is an integer that designates how often a key is generated, in days.
55 * <b>7</b> designates that 1 key will be generated every 7 days starting at 23:59 on the first
56 * Sunday of the year (required).
57 * <p>
58 * <i>timeZone</i> optional argument, example = GMT+5
59 * <p>
60 * <i>endHour</i> optional argument, example = 23
61 * <p>
62 * <i>endMinute</i> optional argument, example = 59
63 * <p>
64 */
65 public static void main(String[] args) {
66 try {
67 if (args.length < 3) {
68 throw new IllegalArgumentException("Invalid argument count.");
69 }
70
71 String varName = args[0];
72 varName = varName.equals("validTrial") || varName.equals("validSub") ? varName + "1" : varName;
73 int dayRate = Integer.valueOf(args[2]);
74
75 Set<String> bytes = new HashSet<>();
76
77 KeyGenerator keygen = KeyGenerator.getInstance("AES");
78 keygen.init(128);
79
80 int maxL = 0;
81 SecretKey sKey;
82 byte[] enc;
83
84 for (int i = 0; i < 365; i += dayRate) {
85 sKey = keygen.generateKey();
86 enc = sKey.getEncoded();
87
88 String s = Arrays.toString(enc).replace(", ", "").replace("-", "");
89 s = s.substring(1, s.length() - 1);
90
91 while (bytes.contains(s)) {
92 sKey = keygen.generateKey();
93 enc = sKey.getEncoded();
94
95 s = Arrays.toString(enc).replace(", ", "").replace("-", "");
96 s = s.substring(1, s.length() - 1);
97 }
98
99 trialKeys.put(i, s);
100 bytes.add(s);
101
102 maxL = Math.max(maxL, s.length());
103 }
104
105 int numSubs = Integer.valueOf(args[1]);
106
107 for (int i = 0; i < numSubs; i++) {
108 sKey = keygen.generateKey();
109 enc = sKey.getEncoded();
110
111 String s = Arrays.toString(enc).replace(", ", "").replace("-", "");
112 s = s.substring(1, s.length() - 1);
113
114 while (bytes.contains(s)) {
115 sKey = keygen.generateKey();
116 enc = sKey.getEncoded();
117
118 s = Arrays.toString(enc).replace(", ", "").replace("-", "");
119 s = s.substring(1, s.length() - 1);
120 }
121
122 subKeys.put(i, s);
123 bytes.add(s);
124
125 maxL = Math.max(maxL, s.length());
126 }
127
128 for (Entry<Integer, String> e : trialKeys.entrySet()) {
129 String key = e.getValue();
130
131 while (key.length() < maxL) {
132 key = "0" + key;
133 }
134
135 trialKeys.put(e.getKey(), key);
136 }
137
138 for (Entry<Integer, String> e : subKeys.entrySet()) {
139 String key = e.getValue();
140
141 while (key.length() < maxL) {
142 key = "0" + key;
143 }
144
145 subKeys.put(e.getKey(), key);
146 }
147
148 String timezone = "default";
149 int hour = 23;
150 int minute = 59;
151
152 if (args.length > 3) {
153 try {
154 hour = Integer.valueOf(args[3]);
155 } catch (NumberFormatException e) {
156 timezone = args[3];
157 }
158
159 if (args.length > 4) {
160 if (timezone.equals("default")) {
161 minute = Integer.valueOf(args[4]);
162 } else {
163 hour = Integer.valueOf(args[4]);
164 }
165
166 if (args.length > 5) {
167 minute = Integer.valueOf(args[5]);
168 }
169 }
170 }
171
172 timezone = timezone.equals("default") ? defaultTZ : timezone;
173 timezone = timezone.trim().replaceAll(" ", "");
174 hour = Math.max(0, Math.min(23, hour));
175 minute = Math.max(0, Math.min(59, minute));
176
177 StringBuilder sb = new StringBuilder("\n\nkey = input(\"\", title=\"Key\")\n\n")
178 .append("t = timenow\n\n")
179 .append("validTrial").append(" = ");
180
181 StringBuilder sb2 = new StringBuilder("// Trial Keys\n\n");
182
183 setFirstSunday(Year.now().getValue());
184
185 calendar.add(Calendar.DATE, -dayRate);
186
187 int pYear = calendar.get(Calendar.YEAR);
188 int pMonth = calendar.get(Calendar.MONTH) + 1;
189 int pDay = calendar.get(Calendar.DAY_OF_MONTH);
190
191 calendar.add(Calendar.DATE, dayRate);
192
193 // for trading view, add + 1 to the month,
194
195 for (Entry<Integer, String> e : trialKeys.entrySet()) {
196 String key = e.getValue();
197
198 int year = calendar.get(Calendar.YEAR);
199 int month = calendar.get(Calendar.MONTH) + 1;
200 int day = calendar.get(Calendar.DAY_OF_MONTH);
201
202 calendar.add(Calendar.DATE, dayRate);
203
204 sb.append("(key == \"").append(key).append("\" and ")
205 .append("t > ").append(timestamp(timezone, pYear, pMonth, pDay, hour, minute))
206 .append(" and t <= ").append(timestamp(timezone, year, month, day, hour, minute))
207 .append(") or ");
208
209 sb2.append("// ").append(key).append(": ").append(
210 formatYearMonthDay(pYear, pMonth, pDay, hour, minute)).append(" ---> ")
211 .append(formatYearMonthDay(year, month, day, hour, minute)).append("\n");
212
213 pYear = year;
214 pMonth = month;
215 pDay = day;
216 }
217
218 String out = sb.toString();
219
220 sb = new StringBuilder(out.substring(0, out.length() - 4))
221 .append("\n\nvalidSub = ");
222
223 for (Entry<Integer, String> e : subKeys.entrySet()) {
224 String key = e.getValue();
225 sb.append("key == \"").append(key).append("\" or ");
226 }
227
228 out = sb.toString();
229
230 sb = new StringBuilder(out.substring(0, out.length() - 4))
231 .append("\n\n").append(varName).append(" = ").append("validTrial or validSub")
232 .append("\n\n").append(sb2.toString())
233 .append("\n\n// Subscription Keys\n\n");
234
235 for (Entry<Integer, String> e : subKeys.entrySet()) {
236 sb.append("// ").append(e.getValue()).append("\n");
237 }
238
239 System.out.println(sb.toString());
240
241 } catch (Exception e) {
242 System.out
243 .println("\nSyntax: expiredVarName:String everyXDays:int timeZone:String endHour:int endMinute:int\n\n"
244 +
245 "validVarName = A boolean true or false if the tested key " +
246 "is currently valid. A valid key is true only if the time stamp " +
247 "associated with that key (if it exists) has not yet expired for a trial, " +
248 "or it is an active subscription key(required)\n\n" +
249 "numMembers = an integer that designates the number of active members subscription " +
250 "keys to generate (required) \n\n" +
251 "everyXDays = an integer that designates how often a key is " +
252 "generated, in days. 7 designates that 1 key will be generated every 7 days starting " +
253 "at endHour:endMinute on the first Sunday of the year (required)\n\n" +
254 "timeZone = Designates the timezone, example = GMT+5 or America/New_York (optional)\n\n" +
255 "endHour = Designates the end hour, example = 23 (optional)\n\n" +
256 "endMinute = Designates the end minute, example = 59 (optional)\n\n" +
257 "Full Example\n\n> valid 20 14 12 0\n\n will generate a 20 member subscription keys, " +
258 "and a trial key every 14 days starting on Sunday at 12:00 PM America/New_York\n");
259
260 e.printStackTrace();
261 }
262 }
263
264 static void setFirstSunday(int year) {
265 setFirstDayOfWeek(year, Calendar.JANUARY, Calendar.SUNDAY);
266 }
267
268 static void setFirstDayOfWeek(int year, int dayofWeek) {
269 setFirstDayOfWeek(year, Calendar.JANUARY, dayofWeek);
270 }
271
272 static void setFirstDayOfWeek(int year, int month, int dayofweek) {
273 calendar.set(Calendar.MONTH, month);
274 calendar.set(Calendar.YEAR, year);
275
276 int dom = 1;
277 calendar.set(Calendar.DAY_OF_MONTH, dom);
278
279 while (calendar.get(Calendar.DAY_OF_WEEK) != dayofweek) {
280 calendar.set(Calendar.DAY_OF_MONTH, ++dom);
281 }
282 }
283
284 static String timestamp(String tz, int year, int month, int dayofmonth, int hour, int minute) {
285 return new StringBuilder("timestamp(\"")
286 .append(tz).append("\", ")
287 .append(year).append(", ")
288 .append(month).append(", ")
289 .append(dayofmonth).append(", ")
290 .append(hour).append(", ")
291 .append(minute)
292 .append(")").toString();
293
294 }
295
296 static String formatYearMonthDay(int year, int month, int day, int hour, int minute) {
297 String m = (month < 10 ? "0" : "") + String.valueOf(month);
298 String d = (day < 10 ? "0" : "") + String.valueOf(day);
299 String h = (hour < 10 ? "0" : "") + String.valueOf(hour);
300 String min = (minute < 10 ? "0" : "") + String.valueOf(minute);
301
302 return new StringBuilder().append(year).append("-").append(m).append("-").append(d).append("-")
303 .append(h).append(":").append(min)
304 .toString();
305
306 }
307}