sliftutils 1.0.2 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,166 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule && mod.default) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
6
+ //exports.addRecord = exports.setRecord = exports.deleteRecord = exports.getRecords = exports.getRecordsRaw = void 0;
7
+ const https_1 = require("socket-function/src/https");
8
+ const caching_1 = require("socket-function/src/caching");
9
+ const fs_1 = __importDefault(require("fs"));
10
+ const batching_1 = require("socket-function/src/batching");
11
+ const SocketFunction_1 = require("socket-function/SocketFunction");
12
+ const DNS_TTLSeconds = {
13
+ "TXT": 60,
14
+ "A": 60,
15
+ };
16
+ const getZoneId = (0, caching_1.cache)(async (rootDomain) => {
17
+ let zones = await cloudflareGETCall("/zones", {});
18
+ let selected = zones.find(x => x.name === rootDomain);
19
+ if (!selected) {
20
+ throw new Error(`Could not find zone for ${rootDomain}. Found ${zones.map(x => x.name).join(", ")}`);
21
+ }
22
+ return selected.id;
23
+ });
24
+ function getRootDomain(key) {
25
+ if (key.endsWith(".")) {
26
+ key = key.slice(0, -1);
27
+ }
28
+ return key.split(".").slice(-2).join(".");
29
+ }
30
+ async function getRecordsRaw(type, key) {
31
+ if (key.endsWith("."))
32
+ key = key.slice(0, -1);
33
+ let zoneId = await getZoneId(getRootDomain(key));
34
+ let results = await cloudflareGETCall(`/zones/${zoneId}/dns_records`);
35
+ return results.filter(x => x.type === type && x.name === key);
36
+ }
37
+ exports.getRecordsRaw = getRecordsRaw;
38
+ async function getRecords(type, key) {
39
+ if (key.endsWith("."))
40
+ key = key.slice(0, -1);
41
+ let raw = await getRecordsRaw(type, key);
42
+ return raw.map(x => x.content);
43
+ }
44
+ exports.getRecords = getRecords;
45
+ async function deleteRecord(type, key, value) {
46
+ if (key.endsWith("."))
47
+ key = key.slice(0, -1);
48
+ let zoneId = await getZoneId(getRootDomain(key));
49
+ let prevValues = await getRecordsRaw(type, key);
50
+ prevValues = prevValues.filter(x => x.content === value);
51
+ if (prevValues.length === 0) {
52
+ if (!SocketFunction_1.SocketFunction.silent) {
53
+ console.log(`No need to delete record, it was not found. ${JSON.stringify(value)} value was not in ${type} for ${key}, values ${JSON.stringify(prevValues.map(x => x.content))}`);
54
+ }
55
+ return;
56
+ }
57
+ console.log(`Removing records of ${type} for ${key}, values ${JSON.stringify(prevValues.map(x => x.content))}`);
58
+ for (let value of prevValues) {
59
+ await cloudflareCall(`/zones/${zoneId}/dns_records/${value.id}`, Buffer.from([]), "DELETE");
60
+ }
61
+ }
62
+ exports.deleteRecord = deleteRecord;
63
+ /** Removes all existing records (unless the record is already present) */
64
+ async function setRecord(type, key, value, proxied) {
65
+ let stack = new Error();
66
+ if (key.endsWith("."))
67
+ key = key.slice(0, -1);
68
+ let zoneId = await getZoneId(getRootDomain(key));
69
+ let prevValues = await getRecordsRaw(type, key);
70
+ // NOTE: Apparently if we try to update by just changing proxied, cloudflare complains and
71
+ // says "an identical record already exists", even though it doesn't, we changed the proxied value...
72
+ if (prevValues.some(x => x.content === value))
73
+ return;
74
+ console.log(`Removing previous records of ${type} for ${key} ${JSON.stringify(prevValues.map(x => x.content))}`);
75
+ let didDeletions = false;
76
+ for (let value of prevValues) {
77
+ didDeletions = true;
78
+ await cloudflareCall(`/zones/${zoneId}/dns_records/${value.id}`, Buffer.from([]), "DELETE");
79
+ }
80
+ console.log(`Setting ${type} record for ${key} to ${value} (previously had ${JSON.stringify(prevValues.map(x => x.content))})`);
81
+ const ttl = DNS_TTLSeconds[type] || 60;
82
+ await cloudflarePOSTCall(`/zones/${zoneId}/dns_records`, {
83
+ type: type,
84
+ name: key,
85
+ content: value,
86
+ ttl,
87
+ proxied: proxied === "proxied",
88
+ });
89
+ // NOTE: Apparently... even if the record didn't exist, we still have to wait...
90
+ console.log(`Waiting ${ttl} seconds for DNS to propagate...`);
91
+ await (0, batching_1.delay)(ttl * 1000);
92
+ console.log(`Done waiting for DNS to update.`);
93
+ }
94
+ exports.setRecord = setRecord;
95
+ /** Keeps existing records */
96
+ async function addRecord(type, key, value, proxied) {
97
+ if (key.endsWith("."))
98
+ key = key.slice(0, -1);
99
+ let zoneId = await getZoneId(getRootDomain(key));
100
+ let prevValues = await getRecordsRaw(type, key);
101
+ // NOTE: Apparently if we try to update by just changing proxied, cloudflare complains and
102
+ // says "an identical record already exists", even though it doesn't, we changed the proxied value...
103
+ if (prevValues.some(x => x.content === value))
104
+ return;
105
+ console.log(`Adding ${type} record for ${key} to ${value} (previously had ${JSON.stringify(prevValues.map(x => x.content))})`);
106
+ const ttl = DNS_TTLSeconds[type] || 60;
107
+ await cloudflarePOSTCall(`/zones/${zoneId}/dns_records`, {
108
+ type: type,
109
+ name: key,
110
+ content: value,
111
+ ttl,
112
+ proxied: proxied === "proxied",
113
+ });
114
+ console.log(`Waiting ${ttl} seconds for DNS to propagate...`);
115
+ await (0, batching_1.delay)(ttl * 1000);
116
+ console.log(`Done waiting for DNS to update.`);
117
+ }
118
+ exports.addRecord = addRecord;
119
+ const getCloudflareCreds = (0, caching_1.lazy)(async () => {
120
+ const path = "cloudflare.json";
121
+ if (!fs_1.default.existsSync(path)) {
122
+ throw new Error(`Must add cloudflare.json file to root of project.`);
123
+ }
124
+ let creds = JSON.parse(fs_1.default.readFileSync(path, "utf8"));
125
+ return {
126
+ key: creds.key,
127
+ };
128
+ });
129
+ async function cloudflareGETCall(path, params) {
130
+ let url = new URL(`https://api.cloudflare.com/client/v4` + path);
131
+ for (let key in params) {
132
+ url.searchParams.set(key, params[key]);
133
+ }
134
+ let creds = await getCloudflareCreds();
135
+ let result = await (0, https_1.httpsRequest)(url.toString(), [], "GET", undefined, {
136
+ headers: {
137
+ "Content-Type": "application/json",
138
+ "Authorization": `Bearer ${creds.key}`,
139
+ }
140
+ });
141
+ let result2 = JSON.parse(result.toString());
142
+ if (!result2.success) {
143
+ throw new Error(`Cloudflare call failed: ${result2.errors.map(x => x.message).join(", ")}`);
144
+ }
145
+ return result2.result;
146
+ }
147
+ async function cloudflarePOSTCall(path, params) {
148
+ return await cloudflareCall(path, Buffer.from(JSON.stringify(params)), "POST");
149
+ }
150
+ async function cloudflareCall(path, payload, method) {
151
+ let url = new URL(`https://api.cloudflare.com/client/v4` + path);
152
+ let creds = await getCloudflareCreds();
153
+ let result = await (0, https_1.httpsRequest)(url.toString(), payload, method, undefined, {
154
+ headers: {
155
+ "Content-Type": "application/json",
156
+ "Authorization": `Bearer ${creds.key}`,
157
+ }
158
+ });
159
+ let result2 = JSON.parse(result.toString());
160
+ if (!result2.success) {
161
+ throw new Error(`Cloudflare call failed: ${result2.errors.map(x => x.message).join(", ")}`);
162
+ }
163
+ return result2.result;
164
+ }
165
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZG5zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiZG5zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLHFEQUF5RDtBQUN6RCx5REFBMEQ7QUFDMUQsNENBQW9CO0FBQ3BCLDJEQUFxRDtBQUNyRCxtRUFBZ0U7QUFFaEUsTUFBTSxjQUFjLEdBQUc7SUFDbkIsS0FBSyxFQUFFLEVBQUU7SUFDVCxHQUFHLEVBQUUsRUFBRTtDQUNWLENBQUM7QUFFRixNQUFNLFNBQVMsR0FBRyxJQUFBLGVBQUssRUFBQyxLQUFLLEVBQUUsVUFBa0IsRUFBbUIsRUFBRTtJQUNsRSxJQUFJLEtBQUssR0FBRyxNQUFNLGlCQUFpQixDQUFpQyxRQUFRLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDbEYsSUFBSSxRQUFRLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLEtBQUssVUFBVSxDQUFDLENBQUM7SUFDdEQsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQ1osTUFBTSxJQUFJLEtBQUssQ0FBQywyQkFBMkIsVUFBVSxXQUFXLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUN6RyxDQUFDO0lBQ0QsT0FBTyxRQUFRLENBQUMsRUFBRSxDQUFDO0FBQ3ZCLENBQUMsQ0FBQyxDQUFDO0FBRUgsU0FBUyxhQUFhLENBQUMsR0FBVztJQUM5QixJQUFJLEdBQUcsQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUNwQixHQUFHLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMzQixDQUFDO0lBQ0QsT0FBTyxHQUFHLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFD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QUksQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsTUFBTSxDQUFDLENBQUM7QUFDbkYsQ0FBQztBQUNELEtBQUssVUFBVSxjQUFjLENBQUksSUFBWSxFQUFFLE9BQWUsRUFBRSxNQUFjO0lBQzFFLElBQUksR0FBRyxHQUFHLElBQUksR0FBRyxDQUFDLHNDQUFzQyxHQUFHLElBQUksQ0FBQyxDQUFDO0lBQ2pFLElBQUksS0FBSyxHQUFHLE1BQU0sa0JBQWtCLEVBQUUsQ0FBQztJQUN2QyxJQUFJLE1BQU0sR0FBRyxNQUFNLElBQUEsb0JBQVksRUFBQyxHQUFHLENBQUMsUUFBUSxFQUFFLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUU7UUFDeEUsT0FBTyxFQUFFO1lBQ0wsY0FBYyxFQUFFLGtCQUFrQjtZQUNsQyxlQUFlLEVBQUUsVUFBVSxLQUFLLENBQUMsR0FBRyxFQUFFO1NBQ3pDO0tBQ0osQ0FBQyxDQUFDO0lBQ0gsSUFBSSxPQUFPLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFLENBQXVGLENBQUM7SUFDbEksSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUNuQixNQUFNLElBQUksS0FBSyxDQUFDLDJCQUEyQixPQUFPLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ2hHLENBQUM7SUFDRCxPQUFPLE9BQU8sQ0FBQyxNQUFXLENBQUM7QUFDL0IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGh0dHBzUmVxdWVzdCB9IGZyb20gXCJzb2NrZXQtZnVuY3Rpb24vc3JjL2h0dHBzXCI7XG5pbXBvcnQgeyBjYWNoZSwgbGF6eSB9IGZyb20gXCJzb2NrZXQtZnVuY3Rpb24vc3JjL2NhY2hpbmdcIjtcbmltcG9ydCBmcyBmcm9tIFwiZnNcIjtcbmltcG9ydCB7IGRlbGF5IH0gZnJvbSBcInNvY2tldC1mdW5jdGlvbi9zcmMvYmF0Y2hpbmdcIjtcbmltcG9ydCB7IFNvY2tldEZ1bmN0aW9uIH0gZnJvbSBcInNvY2tldC1mdW5jdGlvbi9Tb2NrZXRGdW5jdGlvblwiO1xuXG5jb25zdCBETlNfVFRMU2Vjb25kcyA9IHtcbiAgICBcIlRYVFwiOiA2MCxcbiAgICBcIkFcIjogNjAsXG59O1xuXG5jb25zdCBnZXRab25lSWQgPSBjYWNoZShhc3luYyAocm9vdERvbWFpbjogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+ID0+IHtcbiAgICBsZXQgem9uZXMgPSBhd2FpdCBjbG91ZGZsYXJlR0VUQ2FsbDx7IGlkOiBzdHJpbmc7IG5hbWU6IHN0cmluZyB9W10+KFwiL3pvbmVzXCIsIHt9KTtcbiAgICBsZXQgc2VsZWN0ZWQgPSB6b25lcy5maW5kKHggPT4geC5uYW1lID09PSByb290RG9tYWluKTtcbiAgICBpZiAoIXNlbGVjdGVkKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgQ291bGQgbm90IGZpbmQgem9uZSBmb3IgJHtyb290RG9tYWlufS4gRm91bmQgJHt6b25lcy5tYXAoeCA9PiB4Lm5hbWUpLmpvaW4oXCIsIFwiKX1gKTtcbiAgICB9XG4gICAgcmV0dXJuIHNlbGVjdGVkLmlkO1xufSk7XG5cbmZ1bmN0aW9uIGdldFJvb3REb21haW4oa2V5OiBzdHJpbmcpIHtcbiAgICBpZiAoa2V5LmVuZHNXaXRoKFwiLlwiKSkge1xuICAgICAgICBrZXkgPSBrZXkuc2xpY2UoMCwgLTEpO1xuICAgIH1cbiAgICByZXR1cm4ga2V5LnNwbGl0KFwiLlwiKS5zbGljZSgtMikuam9pbihcIi5cIik7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBnZXRSZWNvcmRzUmF3KHR5cGU6IHN0cmluZywga2V5OiBzdHJpbmcpIHtcbiAgICBpZiAoa2V5LmVuZHNXaXRoKFwiLlwiKSkga2V5ID0ga2V5LnNsaWNlKDAsIC0xKTtcbiAgICBsZXQgem9uZUlkID0gYXdhaXQgZ2V0Wm9uZUlkKGdldFJvb3REb21haW4oa2V5KSk7XG4gICAgbGV0IHJlc3VsdHMgPSBhd2FpdCBjbG91ZGZsYXJlR0VUQ2FsbDx7XG4gICAgICAgIGlkOiBzdHJpbmc7XG4gICAgICAgIHR5cGU6IHN0cmluZztcbiAgICAgICAgbmFtZTogc3RyaW5nO1xuICAgICAgICBjb250ZW50OiBzdHJpbmc7XG4gICAgICAgIHByb3hpZWQ6IGJvb2xlYW47XG4gICAgfVtdPihgL3pvbmVzLyR7em9uZUlkfS9kbnNfcmVjb3Jkc2ApO1xuICAgIHJldHVybiByZXN1bHRzLmZpbHRlcih4ID0+IHgudHlwZSA9PT0gdHlwZSAmJiB4Lm5hbWUgPT09IGtleSk7XG59XG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2V0UmVjb3Jkcyh0eXBlOiBzdHJpbmcsIGtleTogc3RyaW5nKSB7XG4gICAgaWYgKGtleS5lbmRzV2l0aChcIi5cIikpIGtleSA9IGtleS5zbGljZSgwLCAtMSk7XG4gICAgbGV0IHJhdyA9IGF3YWl0IGdldFJlY29yZHNSYXcodHlwZSwga2V5KTtcbiAgICByZXR1cm4gcmF3Lm1hcCh4ID0+IHguY29udGVudCk7XG59XG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZGVsZXRlUmVjb3JkKHR5cGU6IHN0cmluZywga2V5OiBzdHJpbmcsIHZhbHVlOiBzdHJpbmcpIHtcbiAgICBpZiAoa2V5LmVuZHNXaXRoKFwiLlwiKSkga2V5ID0ga2V5LnNsaWNlKDAsIC0xKTtcbiAgICBsZXQgem9uZUlkID0gYXdhaXQgZ2V0Wm9uZUlkKGdldFJvb3REb21haW4oa2V5KSk7XG4gICAgbGV0IHByZXZWYWx1ZXMgPSBhd2FpdCBnZXRSZWNvcmRzUmF3KHR5cGUsIGtleSk7XG4gICAgcHJldlZhbHVlcyA9IHByZXZWYWx1ZXMuZmlsdGVyKHggPT4geC5jb250ZW50ID09PSB2YWx1ZSk7XG4gICAgaWYgKHByZXZWYWx1ZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIGlmICghU29ja2V0RnVuY3Rpb24uc2lsZW50KSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhgTm8gbmVlZCB0byBkZWxldGUgcmVjb3JkLCBpdCB3YXMgbm90IGZvdW5kLiAke0pTT04uc3RyaW5naWZ5KHZhbHVlKX0gdmFsdWUgd2FzIG5vdCBpbiAke3R5cGV9IGZvciAke2tleX0sIHZhbHVlcyAke0pTT04uc3RyaW5naWZ5KHByZXZWYWx1ZXMubWFwKHggPT4geC5jb250ZW50KSl9YCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnNvbGUubG9nKGBSZW1vdmluZyByZWNvcmRzIG9mICR7dHlwZX0gZm9yICR7a2V5fSwgdmFsdWVzICR7SlNPTi5zdHJpbmdpZnkocHJldlZhbHVlcy5tYXAoeCA9PiB4LmNvbnRlbnQpKX1gKTtcbiAgICBmb3IgKGxldCB2YWx1ZSBvZiBwcmV2VmFsdWVzKSB7XG4gICAgICAgIGF3YWl0IGNsb3VkZmxhcmVDYWxsKGAvem9uZXMvJHt6b25lSWR9L2Ruc19yZWNvcmRzLyR7dmFsdWUuaWR9YCwgQnVmZmVyLmZyb20oW10pLCBcIkRFTEVURVwiKTtcbiAgICB9XG59XG4vKiogUmVtb3ZlcyBhbGwgZXhpc3RpbmcgcmVjb3JkcyAodW5sZXNzIHRoZSByZWNvcmQgaXMgYWxyZWFkeSBwcmVzZW50KSAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNldFJlY29yZCh0eXBlOiBzdHJpbmcsIGtleTogc3RyaW5nLCB2YWx1ZTogc3RyaW5nLCBwcm94aWVkPzogXCJwcm94aWVkXCIpIHtcbiAgICBsZXQgc3RhY2sgPSBuZXcgRXJyb3IoKTtcbiAgICBpZiAoa2V5LmVuZHNXaXRoKFwiLlwiKSkga2V5ID0ga2V5LnNsaWNlKDAsIC0xKTtcbiAgICBsZXQgem9uZUlkID0gYXdhaXQgZ2V0Wm9uZUlkKGdldFJvb3REb21haW4oa2V5KSk7XG4gICAgbGV0IHByZXZWYWx1ZXMgPSBhd2FpdCBnZXRSZWNvcmRzUmF3KHR5cGUsIGtleSk7XG4gICAgLy8gTk9URTogQXBwYXJlbnRseSBpZiB3ZSB0cnkgdG8gdXBkYXRlIGJ5IGp1c3QgY2hhbmdpbmcgcHJveGllZCwgY2xvdWRmbGFyZSBjb21wbGFpbnMgYW5kXG4gICAgLy8gIHNheXMgXCJhbiBpZGVudGljYWwgcmVjb3JkIGFscmVhZHkgZXhpc3RzXCIsIGV2ZW4gdGhvdWdoIGl0IGRvZXNuJ3QsIHdlIGNoYW5nZWQgdGhlIHByb3hpZWQgdmFsdWUuLi5cbiAgICBpZiAocHJldlZhbHVlcy5zb21lKHggPT4geC5jb250ZW50ID09PSB2YWx1ZSkpIHJldHVybjtcblxuICAgIGNvbnNvbGUubG9nKGBSZW1vdmluZyBwcmV2aW91cyByZWNvcmRzIG9mICR7dHlwZX0gZm9yICR7a2V5fSAke0pTT04uc3RyaW5naWZ5KHByZXZWYWx1ZXMubWFwKHggPT4geC5jb250ZW50KSl9YCk7XG4gICAgbGV0IGRpZERlbGV0aW9ucyA9IGZhbHNlO1xuICAgIGZvciAobGV0IHZhbHVlIG9mIHByZXZWYWx1ZXMpIHtcbiAgICAgICAgZGlkRGVsZXRpb25zID0gdHJ1ZTtcbiAgICAgICAgYXdhaXQgY2xvdWRmbGFyZUNhbGwoYC96b25lcy8ke3pvbmVJZH0vZG5zX3JlY29yZHMvJHt2YWx1ZS5pZH1gLCBCdWZmZXIuZnJvbShbXSksIFwiREVMRVRFXCIpO1xuICAgIH1cblxuICAgIGNvbnNvbGUubG9nKGBTZXR0aW5nICR7dHlwZX0gcmVjb3JkIGZvciAke2tleX0gdG8gJHt2YWx1ZX0gKHByZXZpb3VzbHkgaGFkICR7SlNPTi5zdHJpbmdpZnkocHJldlZhbHVlcy5tYXAoeCA9PiB4LmNvbnRlbnQpKX0pYCk7XG4gICAgY29uc3QgdHRsID0gRE5TX1RUTFNlY29uZHNbdHlwZSBhcyBcIkFcIl0gfHwgNjA7XG4gICAgYXdhaXQgY2xvdWRmbGFyZVBPU1RDYWxsKGAvem9uZXMvJHt6b25lSWR9L2Ruc19yZWNvcmRzYCwge1xuICAgICAgICB0eXBlOiB0eXBlLFxuICAgICAgICBuYW1lOiBrZXksXG4gICAgICAgIGNvbnRlbnQ6IHZhbHVlLFxuICAgICAgICB0dGwsXG4gICAgICAgIHByb3hpZWQ6IHByb3hpZWQgPT09IFwicHJveGllZFwiLFxuICAgIH0pO1xuICAgIC8vIE5PVEU6IEFwcGFyZW50bHkuLi4gZXZlbiBpZiB0aGUgcmVjb3JkIGRpZG4ndCBleGlzdCwgd2Ugc3RpbGwgaGF2ZSB0byB3YWl0Li4uXG4gICAgY29uc29sZS5sb2coYFdhaXRpbmcgJHt0dGx9IHNlY29uZHMgZm9yIEROUyB0byBwcm9wYWdhdGUuLi5gKTtcbiAgICBhd2FpdCBkZWxheSh0dGwgKiAxMDAwKTtcbiAgICBjb25zb2xlLmxvZyhgRG9uZSB3YWl0aW5nIGZvciBETlMgdG8gdXBkYXRlLmApO1xuXG59XG4vKiogS2VlcHMgZXhpc3RpbmcgcmVjb3JkcyAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGFkZFJlY29yZCh0eXBlOiBzdHJpbmcsIGtleTogc3RyaW5nLCB2YWx1ZTogc3RyaW5nLCBwcm94aWVkPzogXCJwcm94aWVkXCIpIHtcbiAgICBpZiAoa2V5LmVuZHNXaXRoKFwiLlwiKSkga2V5ID0ga2V5LnNsaWNlKDAsIC0xKTtcbiAgICBsZXQgem9uZUlkID0gYXdhaXQgZ2V0Wm9uZUlkKGdldFJvb3REb21haW4oa2V5KSk7XG4gICAgbGV0IHByZXZWYWx1ZXMgPSBhd2FpdCBnZXRSZWNvcmRzUmF3KHR5cGUsIGtleSk7XG4gICAgLy8gTk9URTogQXBwYXJlbnRseSBpZiB3ZSB0cnkgdG8gdXBkYXRlIGJ5IGp1c3QgY2hhbmdpbmcgcHJveGllZCwgY2xvdWRmbGFyZSBjb21wbGFpbnMgYW5kXG4gICAgLy8gIHNheXMgXCJhbiBpZGVudGljYWwgcmVjb3JkIGFscmVhZHkgZXhpc3RzXCIsIGV2ZW4gdGhvdWdoIGl0IGRvZXNuJ3QsIHdlIGNoYW5nZWQgdGhlIHByb3hpZWQgdmFsdWUuLi5cbiAgICBpZiAocHJldlZhbHVlcy5zb21lKHggPT4geC5jb250ZW50ID09PSB2YWx1ZSkpIHJldHVybjtcbiAgICBjb25zb2xlLmxvZyhgQWRkaW5nICR7dHlwZX0gcmVjb3JkIGZvciAke2tleX0gdG8gJHt2YWx1ZX0gKHByZXZpb3VzbHkgaGFkICR7SlNPTi5zdHJpbmdpZnkocHJldlZhbHVlcy5tYXAoeCA9PiB4LmNvbnRlbnQpKX0pYCk7XG4gICAgY29uc3QgdHRsID0gRE5TX1RUTFNlY29uZHNbdHlwZSBhcyBcIkFcIl0gfHwgNjA7XG4gICAgYXdhaXQgY2xvdWRmbGFyZVBPU1RDYWxsKGAvem9uZXMvJHt6b25lSWR9L2Ruc19yZWNvcmRzYCwge1xuICAgICAgICB0eXBlOiB0eXBlLFxuICAgICAgICBuYW1lOiBrZXksXG4gICAgICAgIGNvbnRlbnQ6IHZhbHVlLFxuICAgICAgICB0dGwsXG4gICAgICAgIHByb3hpZWQ6IHByb3hpZWQgPT09IFwicHJveGllZFwiLFxuICAgIH0pO1xuICAgIGNvbnNvbGUubG9nKGBXYWl0aW5nICR7dHRsfSBzZWNvbmRzIGZvciBETlMgdG8gcHJvcGFnYXRlLi4uYCk7XG4gICAgYXdhaXQgZGVsYXkodHRsICogMTAwMCk7XG4gICAgY29uc29sZS5sb2coYERvbmUgd2FpdGluZyBmb3IgRE5TIHRvIHVwZGF0ZS5gKTtcbn1cblxuXG5jb25zdCBnZXRDbG91ZGZsYXJlQ3JlZHMgPSBsYXp5KGFzeW5jICgpOiBQcm9taXNlPHsga2V5OiBzdHJpbmc7IH0+ID0+IHtcbiAgICBjb25zdCBwYXRoID0gXCJjbG91ZGZsYXJlLmpzb25cIjtcbiAgICBpZiAoIWZzLmV4aXN0c1N5bmMocGF0aCkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBNdXN0IGFkZCBjbG91ZGZsYXJlLmpzb24gZmlsZSB0byByb290IG9mIHByb2plY3QuYCk7XG4gICAgfVxuICAgIGxldCBjcmVkcyA9IEpTT04ucGFyc2UoZnMucmVhZEZpbGVTeW5jKHBhdGgsIFwidXRmOFwiKSkgYXMgeyBrZXk6IHN0cmluZzsgfTtcbiAgICByZXR1cm4ge1xuICAgICAgICBrZXk6IGNyZWRzLmtleSxcbiAgICB9O1xufSk7XG5cbmFzeW5jIGZ1bmN0aW9uIGNsb3VkZmxhcmVHRVRDYWxsPFQ+KHBhdGg6IHN0cmluZywgcGFyYW1zPzogeyBba2V5OiBzdHJpbmddOiBzdHJpbmcgfSk6IFByb21pc2U8VD4ge1xuICAgIGxldCB1cmwgPSBuZXcgVVJMKGBodHRwczovL2FwaS5jbG91ZGZsYXJlLmNvbS9jbGllbnQvdjRgICsgcGF0aCk7XG4gICAgZm9yIChsZXQga2V5IGluIHBhcmFtcykge1xuICAgICAgICB1cmwuc2VhcmNoUGFyYW1zLnNldChrZXksIHBhcmFtc1trZXldKTtcbiAgICB9XG4gICAgbGV0IGNyZWRzID0gYXdhaXQgZ2V0Q2xvdWRmbGFyZUNyZWRzKCk7XG4gICAgbGV0IHJlc3VsdCA9IGF3YWl0IGh0dHBzUmVxdWVzdCh1cmwudG9TdHJpbmcoKSwgW10sIFwiR0VUXCIsIHVuZGVmaW5lZCwge1xuICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICBcIkNvbnRlbnQtVHlwZVwiOiBcImFwcGxpY2F0aW9uL2pzb25cIixcbiAgICAgICAgICAgIFwiQXV0aG9yaXphdGlvblwiOiBgQmVhcmVyICR7Y3JlZHMua2V5fWAsXG4gICAgICAgIH1cbiAgICB9KTtcbiAgICBsZXQgcmVzdWx0MiA9IEpTT04ucGFyc2UocmVzdWx0LnRvU3RyaW5nKCkpIGFzIHsgcmVzdWx0OiB1bmtub3duOyBzdWNjZXNzOiBib29sZWFuOyBlcnJvcnM6IHsgY29kZTogbnVtYmVyOyBtZXNzYWdlOiBzdHJpbmcgfVtdIH07XG4gICAgaWYgKCFyZXN1bHQyLnN1Y2Nlc3MpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBDbG91ZGZsYXJlIGNhbGwgZmFpbGVkOiAke3Jlc3VsdDIuZXJyb3JzLm1hcCh4ID0+IHgubWVzc2FnZSkuam9pbihcIiwgXCIpfWApO1xuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0Mi5yZXN1bHQgYXMgVDtcbn1cbmFzeW5jIGZ1bmN0aW9uIGNsb3VkZmxhcmVQT1NUQ2FsbDxUPihwYXRoOiBzdHJpbmcsIHBhcmFtczogeyBba2V5OiBzdHJpbmddOiB1bmtub3duIH0pOiBQcm9taXNlPFQ+IHtcbiAgICByZXR1cm4gYXdhaXQgY2xvdWRmbGFyZUNhbGwocGF0aCwgQnVmZmVyLmZyb20oSlNPTi5zdHJpbmdpZnkocGFyYW1zKSksIFwiUE9TVFwiKTtcbn1cbmFzeW5jIGZ1bmN0aW9uIGNsb3VkZmxhcmVDYWxsPFQ+KHBhdGg6IHN0cmluZywgcGF5bG9hZDogQnVmZmVyLCBtZXRob2Q6IHN0cmluZyk6IFByb21pc2U8VD4ge1xuICAgIGxldCB1cmwgPSBuZXcgVVJMKGBodHRwczovL2FwaS5jbG91ZGZsYXJlLmNvbS9jbGllbnQvdjRgICsgcGF0aCk7XG4gICAgbGV0IGNyZWRzID0gYXdhaXQgZ2V0Q2xvdWRmbGFyZUNyZWRzKCk7XG4gICAgbGV0IHJlc3VsdCA9IGF3YWl0IGh0dHBzUmVxdWVzdCh1cmwudG9TdHJpbmcoKSwgcGF5bG9hZCwgbWV0aG9kLCB1bmRlZmluZWQsIHtcbiAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgXCJDb250ZW50LVR5cGVcIjogXCJhcHBsaWNhdGlvbi9qc29uXCIsXG4gICAgICAgICAgICBcIkF1dGhvcml6YXRpb25cIjogYEJlYXJlciAke2NyZWRzLmtleX1gLFxuICAgICAgICB9XG4gICAgfSk7XG4gICAgbGV0IHJlc3VsdDIgPSBKU09OLnBhcnNlKHJlc3VsdC50b1N0cmluZygpKSBhcyB7IHJlc3VsdDogdW5rbm93bjsgc3VjY2VzczogYm9vbGVhbjsgZXJyb3JzOiB7IGNvZGU6IG51bWJlcjsgbWVzc2FnZTogc3RyaW5nIH1bXSB9O1xuICAgIGlmICghcmVzdWx0Mi5zdWNjZXNzKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgQ2xvdWRmbGFyZSBjYWxsIGZhaWxlZDogJHtyZXN1bHQyLmVycm9ycy5tYXAoeCA9PiB4Lm1lc3NhZ2UpLmpvaW4oXCIsIFwiKX1gKTtcbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdDIucmVzdWx0IGFzIFQ7XG59Il19
166
+ /* _JS_SOURCE_HASH = "23ba5542e3de4342e75c1b8db86679523e53f9535c85e9f1b8abd80af92a917c"; */
@@ -0,0 +1,181 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule && mod.default) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
29
+ exports.getHTTPSCert = void 0;
30
+ const dns_1 = require("./dns");
31
+ const caching_1 = require("socket-function/src/caching");
32
+ const forge = __importStar(require("node-forge"));
33
+ const acme_client_1 = __importDefault(require("acme-client"));
34
+ const logColors_1 = require("socket-function/src/formatting/logColors");
35
+ const format_1 = require("socket-function/src/formatting/format");
36
+ const misc_1 = require("socket-function/src/misc");
37
+ const batching_1 = require("socket-function/src/batching");
38
+ const fs_1 = __importDefault(require("fs"));
39
+ const persistentLocalStorage_1 = require("./persistentLocalStorage");
40
+ // Expire EXPIRATION_THRESHOLD% of the way through the certificate's lifetime
41
+ const EXPIRATION_THRESHOLD = 0.4;
42
+ /** NOTE: We also generate the domain *.domain */
43
+ exports.getHTTPSCert = (0, caching_1.cache)(async (domain) => {
44
+ if (!domain.endsWith(".")) {
45
+ domain = domain + ".";
46
+ }
47
+ let keyCert;
48
+ let path = domain + ".cert";
49
+ try {
50
+ keyCert = JSON.parse(fs_1.default.readFileSync(path, "utf8"));
51
+ }
52
+ catch (_a) { }
53
+ if (keyCert) {
54
+ // If 40% of the lifetime has passed, renew it (has to be < the threshold
55
+ // in EdgeCertController).
56
+ let certObj = parseCert(keyCert.cert);
57
+ let expirationTime = +new Date(certObj.validity.notAfter);
58
+ let createTime = +new Date(certObj.validity.notBefore);
59
+ let renewDate = createTime + (expirationTime - createTime) * EXPIRATION_THRESHOLD;
60
+ if (renewDate < Date.now()) {
61
+ console.log((0, logColors_1.magenta)(`Renewing domain ${domain} (renew target is ${(0, format_1.formatDateTime)(renewDate)}).`));
62
+ keyCert = undefined;
63
+ }
64
+ }
65
+ else {
66
+ console.log((0, logColors_1.magenta)(`No cert found for domain ${domain}, generating shortly.`));
67
+ }
68
+ if (keyCert) {
69
+ return keyCert;
70
+ }
71
+ const accountKey = await getAccountKey(domain);
72
+ let altDomains = [];
73
+ // altDomains.push("noproxy." + domain);
74
+ // // NOTE: Allowing local access is just an optimization, not to avoid having to forward ports
75
+ // // (unless you type 127-0-0-1.domain into the browser... then I guess you don't have to forward ports?)
76
+ // altDomains.push("127-0-0-1." + domain);
77
+ // NOTE: I forget why we were not allowing wildcard domains. I think it was to prevent
78
+ // any HTTPS domains from impersonating servers. But... servers have two levels, so that isn't
79
+ // an issue. And even if they didn't they store their public key in their domain, so you
80
+ // can't really impersonate them anyways...
81
+ // - AND, we need this for IP type A records, which... we need to pick the server we want
82
+ // to connect to.
83
+ altDomains.push("*." + domain);
84
+ try {
85
+ keyCert = await generateCert({ accountKey, domain, altDomains });
86
+ }
87
+ catch (e) {
88
+ if (String(e).includes("authorization must be pending")) {
89
+ console.log(`Authorization appears to be pending, waiting 2 minutes for other process to create certificate`);
90
+ await (0, batching_1.delay)(misc_1.timeInMinute * 2);
91
+ return await (0, exports.getHTTPSCert)(domain);
92
+ }
93
+ throw e;
94
+ }
95
+ await fs_1.default.promises.writeFile(path, JSON.stringify(keyCert));
96
+ return keyCert;
97
+ });
98
+ const getAccountKey = async function getAccountKey(domain) {
99
+ let accountKey = (0, persistentLocalStorage_1.getKeyStore)(domain, "letsEncryptAccountKey");
100
+ let secret = await accountKey.get();
101
+ if (!secret) {
102
+ // Should only HAPPEN ONCE, EVER!
103
+ console.error((0, logColors_1.red)(`Generating new letsencrypt account key`));
104
+ const keyPair = forge.pki.rsa.generateKeyPair();
105
+ secret = forge.pki.privateKeyToPem(keyPair.privateKey);
106
+ await accountKey.set(secret);
107
+ }
108
+ return secret;
109
+ };
110
+ function parseCert(PEMorDER) {
111
+ return forge.pki.certificateFromPem(normalizeCertToPEM(PEMorDER));
112
+ }
113
+ function normalizeCertToPEM(PEMorDER) {
114
+ if (PEMorDER.toString().startsWith("-----BEGIN CERTIFICATE-----")) {
115
+ return PEMorDER.toString();
116
+ }
117
+ PEMorDER = PEMorDER.toString("base64");
118
+ return "-----BEGIN CERTIFICATE-----\n" + PEMorDER + "\n-----END CERTIFICATE-----";
119
+ }
120
+ async function generateCert(config) {
121
+ let { accountKey, domain } = config;
122
+ console.log((0, logColors_1.magenta)(`Generating new cert for ${domain}`));
123
+ let domainList = [domain, ...config.altDomains || []];
124
+ // Strip trailing "."
125
+ domainList = domainList.map(x => x.endsWith(".") ? x.slice(0, -1) : x);
126
+ const [certificateKey, certificateCsr] = await acme_client_1.default.forge.createCsr({
127
+ commonName: domainList[0],
128
+ altNames: domainList.slice(1),
129
+ });
130
+ // So... acme-client is fine. Just re-implement the "auto" mode ourselves, to have more control over it.
131
+ const client = new acme_client_1.default.Client({
132
+ directoryUrl: acme_client_1.default.directory.letsencrypt.production,
133
+ accountKey: accountKey,
134
+ });
135
+ const accountPayload = {
136
+ termsOfServiceAgreed: true,
137
+ contact: [`mailto:devops@perspectanalytics.com`],
138
+ };
139
+ try {
140
+ await client.getAccountUrl();
141
+ }
142
+ catch (_a) {
143
+ await client.createAccount(accountPayload);
144
+ }
145
+ const orderPayload = {
146
+ identifiers: domainList.map(domain => ({ type: "dns", value: domain })),
147
+ };
148
+ const order = await client.createOrder(orderPayload);
149
+ const authorizations = await client.getAuthorizations(order);
150
+ console.log(`Starting authorizations: ${JSON.stringify(authorizations)}`);
151
+ for (let auth of authorizations) {
152
+ if (auth.status === "valid") {
153
+ console.log(`Authorization already valid for ${auth.identifier.value}`);
154
+ continue;
155
+ }
156
+ console.log(`Starting authorization for ${JSON.stringify(auth)}`);
157
+ // Only use DNS authorization
158
+ let challenge = auth.challenges.find(x => x.type === "dns-01");
159
+ if (!challenge) {
160
+ throw new Error("No DNS challenge found");
161
+ }
162
+ const keyAuthorization = await client.getChallengeKeyAuthorization(challenge);
163
+ let hostname = auth.identifier.value;
164
+ let challengeRecordName = "_acme-challenge." + hostname + ".";
165
+ await (0, dns_1.setRecord)("TXT", challengeRecordName, keyAuthorization);
166
+ await client.completeChallenge(challenge);
167
+ console.log(`Challenge completed`);
168
+ await client.waitForValidStatus(challenge);
169
+ console.log(`Status of order is valid`);
170
+ }
171
+ const finalized = await client.finalizeOrder(order, certificateCsr);
172
+ console.log(`Order finalized`);
173
+ let cert = await client.getCertificate(finalized);
174
+ return {
175
+ domains: domainList,
176
+ key: certificateKey.toString(),
177
+ cert: cert,
178
+ };
179
+ }
180
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHR0cHNDZXJ0cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImh0dHBzQ2VydHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFDQSwrQkFBdUU7QUFDdkUseURBQTBEO0FBQzFELGtEQUFvQztBQUNwQyw4REFBK0I7QUFDL0Isd0VBQXdFO0FBQ3hFLGtFQUFtRjtBQUNuRixtREFBd0Q7QUFDeEQsMkRBQXFEO0FBQ3JELDRDQUFvQjtBQUNwQixxRUFBdUQ7QUFHdkQsNkVBQTZFO0FBQzdFLE1BQU0sb0JBQW9CLEdBQUcsR0FBRyxDQUFDO0FBRWpDLGlEQUFpRDtBQUNwQyxRQUFBLFlBQVksR0FBRyxJQUFBLGVBQUssRUFBQyxLQUFLLEVBQUUsTUFBYyxFQUEwQyxFQUFFO0lBQy9GLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7UUFDeEIsTUFBTSxHQUFHLE1BQU0sR0FBRyxHQUFHLENBQUM7SUFDMUIsQ0FBQztJQUNELElBQUksT0FBa0QsQ0FBQztJQUN2RCxJQUFJLElBQUksR0FBRyxNQUFNLEdBQUcsT0FBTyxDQUFDO0lBRTVCLElBQUksQ0FBQztRQUNELE9BQU8sR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLFlBQUUsQ0FBQyxZQUFZLENBQUMsSUFBSSxFQUFFLE1BQU0sQ0FBQyxDQUFrQyxDQUFDO0lBQ3pGLENBQUM7SUFBQyxXQUFNLENBQUMsQ0FBQyxDQUFDO0lBQ1gsSUFBSSxPQUFPLEVBQUUsQ0FBQztRQUNWLHlFQUF5RTtRQUN6RSwyQkFBMkI7UUFDM0IsSUFBSSxPQUFPLEdBQUcsU0FBUyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUN0QyxJQUFJLGNBQWMsR0FBRyxDQUFDLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDMUQsSUFBSSxVQUFVLEdBQUcsQ0FBQyxJQUFJLElB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LFVBQVU7UUFDbkIsR0FBRyxFQUFFLGNBQWMsQ0FBQyxRQUFRLEVBQUU7UUFDOUIsSUFBSSxFQUFFLElBQUk7S0FDYixDQUFDO0FBQ04sQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIlxuaW1wb3J0IHsgYWRkUmVjb3JkLCBkZWxldGVSZWNvcmQsIGdldFJlY29yZHMsIHNldFJlY29yZCB9IGZyb20gXCIuL2Ruc1wiO1xuaW1wb3J0IHsgY2FjaGUsIGxhenkgfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL3NyYy9jYWNoaW5nXCI7XG5pbXBvcnQgKiBhcyBmb3JnZSBmcm9tIFwibm9kZS1mb3JnZVwiO1xuaW1wb3J0IGFjbWUgZnJvbSBcImFjbWUtY2xpZW50XCI7XG5pbXBvcnQgeyBtYWdlbnRhLCByZWQgfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL3NyYy9mb3JtYXR0aW5nL2xvZ0NvbG9yc1wiO1xuaW1wb3J0IHsgZm9ybWF0RGF0ZVRpbWUsIGZvcm1hdFRpbWUgfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL3NyYy9mb3JtYXR0aW5nL2Zvcm1hdFwiO1xuaW1wb3J0IHsgdGltZUluTWludXRlIH0gZnJvbSBcInNvY2tldC1mdW5jdGlvbi9zcmMvbWlzY1wiO1xuaW1wb3J0IHsgZGVsYXkgfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL3NyYy9iYXRjaGluZ1wiO1xuaW1wb3J0IGZzIGZyb20gXCJmc1wiO1xuaW1wb3J0IHsgZ2V0S2V5U3RvcmUgfSBmcm9tIFwiLi9wZXJzaXN0ZW50TG9jYWxTdG9yYWdlXCI7XG5cblxuLy8gRXhwaXJlIEVYUElSQVRJT05fVEhSRVNIT0xEJSBvZiB0aGUgd2F5IHRocm91Z2ggdGhlIGNlcnRpZmljYXRlJ3MgbGlmZXRpbWVcbmNvbnN0IEVYUElSQVRJT05fVEhSRVNIT0xEID0gMC40O1xuXG4vKiogTk9URTogV2UgYWxzbyBnZW5lcmF0ZSB0aGUgZG9tYWluICouZG9tYWluICovXG5leHBvcnQgY29uc3QgZ2V0SFRUUFNDZXJ0ID0gY2FjaGUoYXN5bmMgKGRvbWFpbjogc3RyaW5nKTogUHJvbWlzZTx7IGtleTogc3RyaW5nOyBjZXJ0OiBzdHJpbmcgfT4gPT4ge1xuICAgIGlmICghZG9tYWluLmVuZHNXaXRoKFwiLlwiKSkge1xuICAgICAgICBkb21haW4gPSBkb21haW4gKyBcIi5cIjtcbiAgICB9XG4gICAgbGV0IGtleUNlcnQ6IHsga2V5OiBzdHJpbmc7IGNlcnQ6IHN0cmluZyB9IHwgdW5kZWZpbmVkO1xuICAgIGxldCBwYXRoID0gZG9tYWluICsgXCIuY2VydFwiO1xuXG4gICAgdHJ5IHtcbiAgICAgICAga2V5Q2VydCA9IEpTT04ucGFyc2UoZnMucmVhZEZpbGVTeW5jKHBhdGgsIFwidXRmOFwiKSkgYXMgeyBrZXk6IHN0cmluZzsgY2VydDogc3RyaW5nIH07XG4gICAgfSBjYXRjaCB7IH1cbiAgICBpZiAoa2V5Q2VydCkge1xuICAgICAgICAvLyBJZiA0MCUgb2YgdGhlIGxpZmV0aW1lIGhhcyBwYXNzZWQsIHJlbmV3IGl0IChoYXMgdG8gYmUgPCB0aGUgdGhyZXNob2xkXG4gICAgICAgIC8vICBpbiBFZGdlQ2VydENvbnRyb2xsZXIpLlxuICAgICAgICBsZXQgY2VydE9iaiA9IHBhcnNlQ2VydChrZXlDZXJ0LmNlcnQpO1xuICAgICAgICBsZXQgZXhwaXJhdGlvblRpbWUgPSArbmV3IERhdGUoY2VydE9iai52YWxpZGl0eS5ub3RBZnRlcik7XG4gICAgICAgIGxldCBjcmVhdGVUaW1lID0gK25ldyBEYXRlKGNlcnRPYmoudmFsaWRpdHkubm90QmVmb3JlKTtcbiAgICAgICAgbGV0IHJlbmV3RGF0ZSA9IGNyZWF0ZVRpbWUgKyAoZXhwaXJhdGlvblRpbWUgLSBjcmVhdGVUaW1lKSAqIEVYUElSQVRJT05fVEhSRVNIT0xEO1xuICAgICAgICBpZiAocmVuZXdEYXRlIDwgRGF0ZS5ub3coKSkge1xuICAgICAgICAgICAgY29uc29sZS5sb2cobWFnZW50YShgUmVuZXdpbmcgZG9tYWluICR7ZG9tYWlufSAocmVuZXcgdGFyZ2V0IGlzICR7Zm9ybWF0RGF0ZVRpbWUocmVuZXdEYXRlKX0pLmApKTtcbiAgICAgICAgICAgIGtleUNlcnQgPSB1bmRlZmluZWQ7XG4gICAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgICBjb25zb2xlLmxvZyhtYWdlbnRhKGBObyBjZXJ0IGZvdW5kIGZvciBkb21haW4gJHtkb21haW59LCBnZW5lcmF0aW5nIHNob3J0bHkuYCkpO1xuICAgIH1cbiAgICBpZiAoa2V5Q2VydCkge1xuICAgICAgICByZXR1cm4ga2V5Q2VydDtcbiAgICB9XG5cbiAgICBjb25zdCBhY2NvdW50S2V5ID0gYXdhaXQgZ2V0QWNjb3VudEtleShkb21haW4pO1xuICAgIGxldCBhbHREb21haW5zOiBzdHJpbmdbXSA9IFtdO1xuXG4gICAgLy8gYWx0RG9tYWlucy5wdXNoKFwibm9wcm94eS5cIiArIGRvbWFpbik7XG4gICAgLy8gLy8gTk9URTogQWxsb3dpbmcgbG9jYWwgYWNjZXNzIGlzIGp1c3QgYW4gb3B0aW1pemF0aW9uLCBub3QgdG8gYXZvaWQgaGF2aW5nIHRvIGZvcndhcmQgcG9ydHNcbiAgICAvLyAvLyAgKHVubGVzcyB5b3UgdHlwZSAxMjctMC0wLTEuZG9tYWluIGludG8gdGhlIGJyb3dzZXIuLi4gdGhlbiBJIGd1ZXNzIHlvdSBkb24ndCBoYXZlIHRvIGZvcndhcmQgcG9ydHM/KVxuICAgIC8vIGFsdERvbWFpbnMucHVzaChcIjEyNy0wLTAtMS5cIiArIGRvbWFpbik7XG5cbiAgICAvLyBOT1RFOiBJIGZvcmdldCB3aHkgd2Ugd2VyZSBub3QgYWxsb3dpbmcgd2lsZGNhcmQgZG9tYWlucy4gSSB0aGluayBpdCB3YXMgdG8gcHJldmVudFxuICAgIC8vICBhbnkgSFRUUFMgZG9tYWlucyBmcm9tIGltcGVyc29uYXRpbmcgc2VydmVycy4gQnV0Li4uIHNlcnZlcnMgaGF2ZSB0d28gbGV2ZWxzLCBzbyB0aGF0IGlzbid0XG4gICAgLy8gIGFuIGlzc3VlLiBBbmQgZXZlbiBpZiB0aGV5IGRpZG4ndCB0aGV5IHN0b3JlIHRoZWlyIHB1YmxpYyBrZXkgaW4gdGhlaXIgZG9tYWluLCBzbyB5b3VcbiAgICAvLyAgY2FuJ3QgcmVhbGx5IGltcGVyc29uYXRlIHRoZW0gYW55d2F5cy4uLlxuICAgIC8vICAtIEFORCwgd2UgbmVlZCB0aGlzIGZvciBJUCB0eXBlIEEgcmVjb3Jkcywgd2hpY2guLi4gd2UgbmVlZCB0byBwaWNrIHRoZSBzZXJ2ZXIgd2Ugd2FudFxuICAgIC8vICAgICAgdG8gY29ubmVjdCB0by5cbiAgICBhbHREb21haW5zLnB1c2goXCIqLlwiICsgZG9tYWluKTtcblxuICAgIHRyeSB7XG4gICAgICAgIGtleUNlcnQgPSBhd2FpdCBnZW5lcmF0ZUNlcnQoeyBhY2NvdW50S2V5LCBkb21haW4sIGFsdERvbWFpbnMgfSk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBpZiAoU3RyaW5nKGUpLmluY2x1ZGVzKFwiYXV0aG9yaXphdGlvbiBtdXN0IGJlIHBlbmRpbmdcIikpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKGBBdXRob3JpemF0aW9uIGFwcGVhcnMgdG8gYmUgcGVuZGluZywgd2FpdGluZyAyIG1pbnV0ZXMgZm9yIG90aGVyIHByb2Nlc3MgdG8gY3JlYXRlIGNlcnRpZmljYXRlYCk7XG4gICAgICAgICAgICBhd2FpdCBkZWxheSh0aW1lSW5NaW51dGUgKiAyKTtcbiAgICAgICAgICAgIHJldHVybiBhd2FpdCBnZXRIVFRQU0NlcnQoZG9tYWluKTtcbiAgICAgICAgfVxuICAgICAgICB0aHJvdyBlO1xuICAgIH1cbiAgICBhd2FpdCBmcy5wcm9taXNlcy53cml0ZUZpbGUocGF0aCwgSlNPTi5zdHJpbmdpZnkoa2V5Q2VydCkpO1xuICAgIHJldHVybiBrZXlDZXJ0O1xufSk7XG5cblxuY29uc3QgZ2V0QWNjb3VudEtleSA9IGFzeW5jIGZ1bmN0aW9uIGdldEFjY291bnRLZXkoZG9tYWluOiBzdHJpbmcpIHtcbiAgICBsZXQgYWNjb3VudEtleSA9IGdldEtleVN0b3JlPHN0cmluZz4oZG9tYWluLCBcImxldHNFbmNyeXB0QWNjb3VudEtleVwiKTtcbiAgICBsZXQgc2VjcmV0ID0gYXdhaXQgYWNjb3VudEtleS5nZXQoKTtcbiAgICBpZiAoIXNlY3JldCkge1xuICAgICAgICAvLyBTaG91bGQgb25seSBIQVBQRU4gT05DRSwgRVZFUiFcbiAgICAgICAgY29uc29sZS5lcnJvcihyZWQoYEdlbmVyYXRpbmcgbmV3IGxldHNlbmNyeXB0IGFjY291bnQga2V5YCkpO1xuICAgICAgICBjb25zdCBrZXlQYWlyID0gZm9yZ2UucGtpLnJzYS5nZW5lcmF0ZUtleVBhaXIoKTtcbiAgICAgICAgc2VjcmV0ID0gZm9yZ2UucGtpLnByaXZhdGVLZXlUb1BlbShrZXlQYWlyLnByaXZhdGVLZXkpO1xuICAgICAgICBhd2FpdCBhY2NvdW50S2V5LnNldChzZWNyZXQpO1xuICAgIH1cbiAgICByZXR1cm4gc2VjcmV0O1xufTtcblxuXG5mdW5jdGlvbiBwYXJzZUNlcnQoUEVNb3JERVI6IHN0cmluZyB8IEJ1ZmZlcikge1xuICAgIHJldHVybiBmb3JnZS5wa2kuY2VydGlmaWNhdGVGcm9tUGVtKG5vcm1hbGl6ZUNlcnRUb1BFTShQRU1vckRFUikpO1xufVxuXG5mdW5jdGlvbiBub3JtYWxpemVDZXJ0VG9QRU0oUEVNb3JERVI6IHN0cmluZyB8IEJ1ZmZlcik6IHN0cmluZyB7XG4gICAgaWYgKFBFTW9yREVSLnRvU3RyaW5nKCkuc3RhcnRzV2l0aChcIi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLVwiKSkge1xuICAgICAgICByZXR1cm4gUEVNb3JERVIudG9TdHJpbmcoKTtcbiAgICB9XG4gICAgUEVNb3JERVIgPSBQRU1vckRFUi50b1N0cmluZyhcImJhc2U2NFwiKTtcbiAgICByZXR1cm4gXCItLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS1cXG5cIiArIFBFTW9yREVSICsgXCJcXG4tLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tXCI7XG59XG5cblxuYXN5bmMgZnVuY3Rpb24gZ2VuZXJhdGVDZXJ0KGNvbmZpZzoge1xuICAgIGFjY291bnRLZXk6IHN0cmluZztcbiAgICBkb21haW46IHN0cmluZztcbiAgICBhbHREb21haW5zPzogc3RyaW5nW107XG59KTogUHJvbWlzZTx7XG4gICAgZG9tYWluczogc3RyaW5nW107XG4gICAga2V5OiBzdHJpbmc7XG4gICAgY2VydDogc3RyaW5nO1xufT4ge1xuICAgIGxldCB7IGFjY291bnRLZXksIGRvbWFpbiB9ID0gY29uZmlnO1xuXG4gICAgY29uc29sZS5sb2cobWFnZW50YShgR2VuZXJhdGluZyBuZXcgY2VydCBmb3IgJHtkb21haW59YCkpO1xuXG4gICAgbGV0IGRvbWFpbkxpc3QgPSBbZG9tYWluLCAuLi5jb25maWcuYWx0RG9tYWlucyB8fCBbXV07XG4gICAgLy8gU3RyaXAgdHJhaWxpbmcgXCIuXCJcbiAgICBkb21haW5MaXN0ID0gZG9tYWluTGlzdC5tYXAoeCA9PiB4LmVuZHNXaXRoKFwiLlwiKSA/IHguc2xpY2UoMCwgLTEpIDogeCk7XG5cbiAgICBjb25zdCBbY2VydGlmaWNhdGVLZXksIGNlcnRpZmljYXRlQ3NyXSA9IGF3YWl0IGFjbWUuZm9yZ2UuY3JlYXRlQ3NyKHtcbiAgICAgICAgY29tbW9uTmFtZTogZG9tYWluTGlzdFswXSxcbiAgICAgICAgYWx0TmFtZXM6IGRvbWFpbkxpc3Quc2xpY2UoMSksXG4gICAgfSk7XG5cbiAgICAvLyBTby4uLiBhY21lLWNsaWVudCBpcyBmaW5lLiBKdXN0IHJlLWltcGxlbWVudCB0aGUgXCJhdXRvXCIgbW9kZSBvdXJzZWx2ZXMsIHRvIGhhdmUgbW9yZSBjb250cm9sIG92ZXIgaXQuXG4gICAgY29uc3QgY2xpZW50ID0gbmV3IGFjbWUuQ2xpZW50KHtcbiAgICAgICAgZGlyZWN0b3J5VXJsOiBhY21lLmRpcmVjdG9yeS5sZXRzZW5jcnlwdC5wcm9kdWN0aW9uLFxuICAgICAgICBhY2NvdW50S2V5OiBhY2NvdW50S2V5LFxuICAgIH0pO1xuXG4gICAgY29uc3QgYWNjb3VudFBheWxvYWQgPSB7XG4gICAgICAgIHRlcm1zT2ZTZXJ2aWNlQWdyZWVkOiB0cnVlLFxuICAgICAgICBjb250YWN0OiBbYG1haWx0bzpkZXZvcHNAcGVyc3BlY3RhbmFseXRpY3MuY29tYF0sXG4gICAgfTtcblxuICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IGNsaWVudC5nZXRBY2NvdW50VXJsKCk7XG4gICAgfSBjYXRjaCB7XG4gICAgICAgIGF3YWl0IGNsaWVudC5jcmVhdGVBY2NvdW50KGFjY291bnRQYXlsb2FkKTtcbiAgICB9XG5cbiAgICBjb25zdCBvcmRlclBheWxvYWQgPSB7XG4gICAgICAgIGlkZW50aWZpZXJzOiBkb21haW5MaXN0Lm1hcChkb21haW4gPT4gKHsgdHlwZTogXCJkbnNcIiwgdmFsdWU6IGRvbWFpbiB9KSksXG4gICAgfTtcbiAgICBjb25zdCBvcmRlciA9IGF3YWl0IGNsaWVudC5jcmVhdGVPcmRlcihvcmRlclBheWxvYWQpO1xuICAgIGNvbnN0IGF1dGhvcml6YXRpb25zID0gYXdhaXQgY2xpZW50LmdldEF1dGhvcml6YXRpb25zKG9yZGVyKTtcbiAgICBjb25zb2xlLmxvZyhgU3RhcnRpbmcgYXV0aG9yaXphdGlvbnM6ICR7SlNPTi5zdHJpbmdpZnkoYXV0aG9yaXphdGlvbnMpfWApO1xuXG4gICAgZm9yIChsZXQgYXV0aCBvZiBhdXRob3JpemF0aW9ucykge1xuICAgICAgICBpZiAoYXV0aC5zdGF0dXMgPT09IFwidmFsaWRcIikge1xuICAgICAgICAgICAgY29uc29sZS5sb2coYEF1dGhvcml6YXRpb24gYWxyZWFkeSB2YWxpZCBmb3IgJHthdXRoLmlkZW50aWZpZXIudmFsdWV9YCk7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgICBjb25zb2xlLmxvZyhgU3RhcnRpbmcgYXV0aG9yaXphdGlvbiBmb3IgJHtKU09OLnN0cmluZ2lmeShhdXRoKX1gKTtcblxuICAgICAgICAvLyBPbmx5IHVzZSBETlMgYXV0aG9yaXphdGlvblxuICAgICAgICBsZXQgY2hhbGxlbmdlID0gYXV0aC5jaGFsbGVuZ2VzLmZpbmQoeCA9PiB4LnR5cGUgPT09IFwiZG5zLTAxXCIpO1xuICAgICAgICBpZiAoIWNoYWxsZW5nZSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiTm8gRE5TIGNoYWxsZW5nZSBmb3VuZFwiKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBrZXlBdXRob3JpemF0aW9uID0gYXdhaXQgY2xpZW50LmdldENoYWxsZW5nZUtleUF1dGhvcml6YXRpb24oY2hhbGxlbmdlKTtcblxuICAgICAgICBsZXQgaG9zdG5hbWUgPSBhdXRoLmlkZW50aWZpZXIudmFsdWU7XG4gICAgICAgIGxldCBjaGFsbGVuZ2VSZWNvcmROYW1lID0gXCJfYWNtZS1jaGFsbGVuZ2UuXCIgKyBob3N0bmFtZSArIFwiLlwiO1xuICAgICAgICBhd2FpdCBzZXRSZWNvcmQoXCJUWFRcIiwgY2hhbGxlbmdlUmVjb3JkTmFtZSwga2V5QXV0aG9yaXphdGlvbik7XG5cbiAgICAgICAgYXdhaXQgY2xpZW50LmNvbXBsZXRlQ2hhbGxlbmdlKGNoYWxsZW5nZSk7XG4gICAgICAgIGNvbnNvbGUubG9nKGBDaGFsbGVuZ2UgY29tcGxldGVkYCk7XG5cbiAgICAgICAgYXdhaXQgY2xpZW50LndhaXRGb3JWYWxpZFN0YXR1cyhjaGFsbGVuZ2UpO1xuICAgICAgICBjb25zb2xlLmxvZyhgU3RhdHVzIG9mIG9yZGVyIGlzIHZhbGlkYCk7XG4gICAgfVxuXG4gICAgY29uc3QgZmluYWxpemVkID0gYXdhaXQgY2xpZW50LmZpbmFsaXplT3JkZXIob3JkZXIsIGNlcnRpZmljYXRlQ3NyKTtcbiAgICBjb25zb2xlLmxvZyhgT3JkZXIgZmluYWxpemVkYCk7XG5cbiAgICBsZXQgY2VydCA9IGF3YWl0IGNsaWVudC5nZXRDZXJ0aWZpY2F0ZShmaW5hbGl6ZWQpO1xuICAgIHJldHVybiB7XG4gICAgICAgIGRvbWFpbnM6IGRvbWFpbkxpc3QsXG4gICAgICAgIGtleTogY2VydGlmaWNhdGVLZXkudG9TdHJpbmcoKSxcbiAgICAgICAgY2VydDogY2VydCxcbiAgICB9O1xufVxuIl19
181
+ /* _JS_SOURCE_HASH = "4d56068f29ee3700832b43eb0cee884139d4fe1f48558129ee9da54ea1825056"; */
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule && mod.default) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
6
+ //exports.getKeyStore = void 0;
7
+ const misc_1 = require("socket-function/src/misc");
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const os_1 = __importDefault(require("os"));
10
+ function getKeyStore(appName, key) {
11
+ if ((0, misc_1.isNode)()) {
12
+ let path = os_1.default.homedir() + `/keystore_${appName}_` + key + ".json";
13
+ return {
14
+ get() {
15
+ let contents = undefined;
16
+ try {
17
+ contents = fs_1.default.readFileSync(path, "utf8");
18
+ }
19
+ catch (_a) { }
20
+ if (!contents)
21
+ return undefined;
22
+ return JSON.parse(contents);
23
+ },
24
+ set(value) {
25
+ fs_1.default.writeFileSync(path, JSON.stringify(value));
26
+ }
27
+ };
28
+ }
29
+ else {
30
+ return {
31
+ get() {
32
+ let json = localStorage.getItem(key);
33
+ if (!json)
34
+ return undefined;
35
+ return JSON.parse(json);
36
+ },
37
+ set(value) {
38
+ localStorage.setItem(key, JSON.stringify(value));
39
+ }
40
+ };
41
+ }
42
+ }
43
+ exports.getKeyStore = getKeyStore;
44
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGVyc2lzdGVudExvY2FsU3RvcmFnZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInBlcnNpc3RlbnRMb2NhbFN0b3JhZ2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsbURBQWtEO0FBQ2xELDRDQUFvQjtBQUNwQiw0Q0FBb0I7QUFJcEIsU0FBZ0IsV0FBVyxDQUFJLE9BQWUsRUFBRSxHQUFXO0lBSXZELElBQUksSUFBQSxhQUFNLEdBQUUsRUFBRSxDQUFDO1FBQ1gsSUFBSSxJQUFJLEdBQUcsWUFBRSxDQUFDLE9BQU8sRUFBRSxHQUFHLGFBQWEsT0FBTyxHQUFHLEdBQUcsR0FBRyxHQUFHLE9BQU8sQ0FBQztRQUNsRSxPQUFPO1lBQ0gsR0FBRztnQkFDQyxJQUFJLFFBQVEsR0FBdUIsU0FBUyxDQUFDO2dCQUM3QyxJQUFJLENBQUM7b0JBQUMsUUFBUSxHQUFHLFlBQUUsQ0FBQyxZQUFZLENBQUMsSUFBSSxFQUFFLE1BQU0sQ0FBQyxDQUFDO2dCQUFDLENBQUM7Z0JBQUMsV0FBTSxDQUFDLENBQUMsQ0FBQztnQkFDM0QsSUFBSSxDQUFDLFFBQVE7b0JBQUUsT0FBTyxTQUFTLENBQUM7Z0JBQ2hDLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQU0sQ0FBQztZQUNyQyxDQUFDO1lBQ0QsR0FBRyxDQUFDLEtBQWU7Z0JBQ2YsWUFBRSxDQUFDLGFBQWEsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO1lBQ2xELENBQUM7U0FDSixDQUFDO0lBQ04sQ0FBQztTQUFNLENBQUM7UUFDSixPQUFPO1lBQ0gsR0FBRztnQkFDQyxJQUFJLElBQUksR0FBRyxZQUFZLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDO2dCQUNyQyxJQUFJLENBQUMsSUFBSTtvQkFBRSxPQUFPLFNBQVMsQ0FBQztnQkFDNUIsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBTSxDQUFDO1lBQ2pDLENBQUM7WUFDRCxHQUFHLENBQUMsS0FBZTtnQkFDZixZQUFZLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7WUFDckQsQ0FBQztTQUNKLENBQUM7SUFDTixDQUFDO0FBQ0wsQ0FBQztBQTdCRCxrQ0E2QkMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBpc05vZGUgfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL3NyYy9taXNjXCI7XG5pbXBvcnQgZnMgZnJvbSBcImZzXCI7XG5pbXBvcnQgb3MgZnJvbSBcIm9zXCI7XG5pbXBvcnQgeyBNYXliZVByb21pc2UgfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL3NyYy90eXBlc1wiO1xuaW1wb3J0IHsgY2FjaGUgfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL3NyYy9jYWNoaW5nXCI7XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRLZXlTdG9yZTxUPihhcHBOYW1lOiBzdHJpbmcsIGtleTogc3RyaW5nKToge1xuICAgIGdldCgpOiBNYXliZVByb21pc2U8VCB8IHVuZGVmaW5lZD47XG4gICAgc2V0KHZhbHVlOiBUIHwgbnVsbCk6IE1heWJlUHJvbWlzZTx2b2lkPjtcbn0ge1xuICAgIGlmIChpc05vZGUoKSkge1xuICAgICAgICBsZXQgcGF0aCA9IG9zLmhvbWVkaXIoKSArIGAva2V5c3RvcmVfJHthcHBOYW1lfV9gICsga2V5ICsgXCIuanNvblwiO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgZ2V0KCkge1xuICAgICAgICAgICAgICAgIGxldCBjb250ZW50czogc3RyaW5nIHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgIHRyeSB7IGNvbnRlbnRzID0gZnMucmVhZEZpbGVTeW5jKHBhdGgsIFwidXRmOFwiKTsgfSBjYXRjaCB7IH1cbiAgICAgICAgICAgICAgICBpZiAoIWNvbnRlbnRzKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgIHJldHVybiBKU09OLnBhcnNlKGNvbnRlbnRzKSBhcyBUO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHNldCh2YWx1ZTogVCB8IG51bGwpIHtcbiAgICAgICAgICAgICAgICBmcy53cml0ZUZpbGVTeW5jKHBhdGgsIEpTT04uc3RyaW5naWZ5KHZhbHVlKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGdldCgpIHtcbiAgICAgICAgICAgICAgICBsZXQganNvbiA9IGxvY2FsU3RvcmFnZS5nZXRJdGVtKGtleSk7XG4gICAgICAgICAgICAgICAgaWYgKCFqc29uKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgIHJldHVybiBKU09OLnBhcnNlKGpzb24pIGFzIFQ7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgc2V0KHZhbHVlOiBUIHwgbnVsbCkge1xuICAgICAgICAgICAgICAgIGxvY2FsU3RvcmFnZS5zZXRJdGVtKGtleSwgSlNPTi5zdHJpbmdpZnkodmFsdWUpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICB9XG59Il19
45
+ /* _JS_SOURCE_HASH = "fab658bfd6afe5a0e23dd617216d46662e36d867c7ac2a1d0b56d0ac77e47290"; */
@@ -0,0 +1,13 @@
1
+ export declare function getRecordsRaw(type: string, key: string): Promise<{
2
+ id: string;
3
+ type: string;
4
+ name: string;
5
+ content: string;
6
+ proxied: boolean;
7
+ }[]>;
8
+ export declare function getRecords(type: string, key: string): Promise<string[]>;
9
+ export declare function deleteRecord(type: string, key: string, value: string): Promise<void>;
10
+ /** Removes all existing records (unless the record is already present) */
11
+ export declare function setRecord(type: string, key: string, value: string, proxied?: "proxied"): Promise<void>;
12
+ /** Keeps existing records */
13
+ export declare function addRecord(type: string, key: string, value: string, proxied?: "proxied"): Promise<void>;
@@ -0,0 +1,163 @@
1
+ import { httpsRequest } from "socket-function/src/https";
2
+ import { cache, lazy } from "socket-function/src/caching";
3
+ import fs from "fs";
4
+ import { delay } from "socket-function/src/batching";
5
+ import { SocketFunction } from "socket-function/SocketFunction";
6
+
7
+ const DNS_TTLSeconds = {
8
+ "TXT": 60,
9
+ "A": 60,
10
+ };
11
+
12
+ const getZoneId = cache(async (rootDomain: string): Promise<string> => {
13
+ let zones = await cloudflareGETCall<{ id: string; name: string }[]>("/zones", {});
14
+ let selected = zones.find(x => x.name === rootDomain);
15
+ if (!selected) {
16
+ throw new Error(`Could not find zone for ${rootDomain}. Found ${zones.map(x => x.name).join(", ")}`);
17
+ }
18
+ return selected.id;
19
+ });
20
+
21
+ function getRootDomain(key: string) {
22
+ if (key.endsWith(".")) {
23
+ key = key.slice(0, -1);
24
+ }
25
+ return key.split(".").slice(-2).join(".");
26
+ }
27
+
28
+ export async function getRecordsRaw(type: string, key: string) {
29
+ if (key.endsWith(".")) key = key.slice(0, -1);
30
+ let zoneId = await getZoneId(getRootDomain(key));
31
+ let results = await cloudflareGETCall<{
32
+ id: string;
33
+ type: string;
34
+ name: string;
35
+ content: string;
36
+ proxied: boolean;
37
+ }[]>(`/zones/${zoneId}/dns_records`);
38
+ return results.filter(x => x.type === type && x.name === key);
39
+ }
40
+ export async function getRecords(type: string, key: string) {
41
+ if (key.endsWith(".")) key = key.slice(0, -1);
42
+ let raw = await getRecordsRaw(type, key);
43
+ return raw.map(x => x.content);
44
+ }
45
+ export async function deleteRecord(type: string, key: string, value: string) {
46
+ if (key.endsWith(".")) key = key.slice(0, -1);
47
+ let zoneId = await getZoneId(getRootDomain(key));
48
+ let prevValues = await getRecordsRaw(type, key);
49
+ prevValues = prevValues.filter(x => x.content === value);
50
+ if (prevValues.length === 0) {
51
+ if (!SocketFunction.silent) {
52
+ console.log(`No need to delete record, it was not found. ${JSON.stringify(value)} value was not in ${type} for ${key}, values ${JSON.stringify(prevValues.map(x => x.content))}`);
53
+ }
54
+ return;
55
+ }
56
+
57
+ console.log(`Removing records of ${type} for ${key}, values ${JSON.stringify(prevValues.map(x => x.content))}`);
58
+ for (let value of prevValues) {
59
+ await cloudflareCall(`/zones/${zoneId}/dns_records/${value.id}`, Buffer.from([]), "DELETE");
60
+ }
61
+ }
62
+ /** Removes all existing records (unless the record is already present) */
63
+ export async function setRecord(type: string, key: string, value: string, proxied?: "proxied") {
64
+ let stack = new Error();
65
+ if (key.endsWith(".")) key = key.slice(0, -1);
66
+ let zoneId = await getZoneId(getRootDomain(key));
67
+ let prevValues = await getRecordsRaw(type, key);
68
+ // NOTE: Apparently if we try to update by just changing proxied, cloudflare complains and
69
+ // says "an identical record already exists", even though it doesn't, we changed the proxied value...
70
+ if (prevValues.some(x => x.content === value)) return;
71
+
72
+ console.log(`Removing previous records of ${type} for ${key} ${JSON.stringify(prevValues.map(x => x.content))}`);
73
+ let didDeletions = false;
74
+ for (let value of prevValues) {
75
+ didDeletions = true;
76
+ await cloudflareCall(`/zones/${zoneId}/dns_records/${value.id}`, Buffer.from([]), "DELETE");
77
+ }
78
+
79
+ console.log(`Setting ${type} record for ${key} to ${value} (previously had ${JSON.stringify(prevValues.map(x => x.content))})`);
80
+ const ttl = DNS_TTLSeconds[type as "A"] || 60;
81
+ await cloudflarePOSTCall(`/zones/${zoneId}/dns_records`, {
82
+ type: type,
83
+ name: key,
84
+ content: value,
85
+ ttl,
86
+ proxied: proxied === "proxied",
87
+ });
88
+ // NOTE: Apparently... even if the record didn't exist, we still have to wait...
89
+ console.log(`Waiting ${ttl} seconds for DNS to propagate...`);
90
+ await delay(ttl * 1000);
91
+ console.log(`Done waiting for DNS to update.`);
92
+
93
+ }
94
+ /** Keeps existing records */
95
+ export async function addRecord(type: string, key: string, value: string, proxied?: "proxied") {
96
+ if (key.endsWith(".")) key = key.slice(0, -1);
97
+ let zoneId = await getZoneId(getRootDomain(key));
98
+ let prevValues = await getRecordsRaw(type, key);
99
+ // NOTE: Apparently if we try to update by just changing proxied, cloudflare complains and
100
+ // says "an identical record already exists", even though it doesn't, we changed the proxied value...
101
+ if (prevValues.some(x => x.content === value)) return;
102
+ console.log(`Adding ${type} record for ${key} to ${value} (previously had ${JSON.stringify(prevValues.map(x => x.content))})`);
103
+ const ttl = DNS_TTLSeconds[type as "A"] || 60;
104
+ await cloudflarePOSTCall(`/zones/${zoneId}/dns_records`, {
105
+ type: type,
106
+ name: key,
107
+ content: value,
108
+ ttl,
109
+ proxied: proxied === "proxied",
110
+ });
111
+ console.log(`Waiting ${ttl} seconds for DNS to propagate...`);
112
+ await delay(ttl * 1000);
113
+ console.log(`Done waiting for DNS to update.`);
114
+ }
115
+
116
+
117
+ const getCloudflareCreds = lazy(async (): Promise<{ key: string; }> => {
118
+ const path = "cloudflare.json";
119
+ if (!fs.existsSync(path)) {
120
+ throw new Error(`Must add cloudflare.json file to root of project.`);
121
+ }
122
+ let creds = JSON.parse(fs.readFileSync(path, "utf8")) as { key: string; };
123
+ return {
124
+ key: creds.key,
125
+ };
126
+ });
127
+
128
+ async function cloudflareGETCall<T>(path: string, params?: { [key: string]: string }): Promise<T> {
129
+ let url = new URL(`https://api.cloudflare.com/client/v4` + path);
130
+ for (let key in params) {
131
+ url.searchParams.set(key, params[key]);
132
+ }
133
+ let creds = await getCloudflareCreds();
134
+ let result = await httpsRequest(url.toString(), [], "GET", undefined, {
135
+ headers: {
136
+ "Content-Type": "application/json",
137
+ "Authorization": `Bearer ${creds.key}`,
138
+ }
139
+ });
140
+ let result2 = JSON.parse(result.toString()) as { result: unknown; success: boolean; errors: { code: number; message: string }[] };
141
+ if (!result2.success) {
142
+ throw new Error(`Cloudflare call failed: ${result2.errors.map(x => x.message).join(", ")}`);
143
+ }
144
+ return result2.result as T;
145
+ }
146
+ async function cloudflarePOSTCall<T>(path: string, params: { [key: string]: unknown }): Promise<T> {
147
+ return await cloudflareCall(path, Buffer.from(JSON.stringify(params)), "POST");
148
+ }
149
+ async function cloudflareCall<T>(path: string, payload: Buffer, method: string): Promise<T> {
150
+ let url = new URL(`https://api.cloudflare.com/client/v4` + path);
151
+ let creds = await getCloudflareCreds();
152
+ let result = await httpsRequest(url.toString(), payload, method, undefined, {
153
+ headers: {
154
+ "Content-Type": "application/json",
155
+ "Authorization": `Bearer ${creds.key}`,
156
+ }
157
+ });
158
+ let result2 = JSON.parse(result.toString()) as { result: unknown; success: boolean; errors: { code: number; message: string }[] };
159
+ if (!result2.success) {
160
+ throw new Error(`Cloudflare call failed: ${result2.errors.map(x => x.message).join(", ")}`);
161
+ }
162
+ return result2.result as T;
163
+ }