@lordbex/thelounge 4.4.3-blowfish

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.
Files changed (148) hide show
  1. package/.thelounge_home +1 -0
  2. package/LICENSE +22 -0
  3. package/README.md +95 -0
  4. package/client/index.html.tpl +69 -0
  5. package/dist/defaults/config.js +465 -0
  6. package/dist/package.json +174 -0
  7. package/dist/server/client.js +678 -0
  8. package/dist/server/clientManager.js +220 -0
  9. package/dist/server/command-line/index.js +85 -0
  10. package/dist/server/command-line/install.js +123 -0
  11. package/dist/server/command-line/outdated.js +30 -0
  12. package/dist/server/command-line/start.js +34 -0
  13. package/dist/server/command-line/storage.js +103 -0
  14. package/dist/server/command-line/uninstall.js +40 -0
  15. package/dist/server/command-line/upgrade.js +64 -0
  16. package/dist/server/command-line/users/add.js +67 -0
  17. package/dist/server/command-line/users/edit.js +39 -0
  18. package/dist/server/command-line/users/index.js +17 -0
  19. package/dist/server/command-line/users/list.js +53 -0
  20. package/dist/server/command-line/users/remove.js +37 -0
  21. package/dist/server/command-line/users/reset.js +64 -0
  22. package/dist/server/command-line/utils.js +177 -0
  23. package/dist/server/config.js +138 -0
  24. package/dist/server/helper.js +161 -0
  25. package/dist/server/identification.js +139 -0
  26. package/dist/server/index.js +3 -0
  27. package/dist/server/log.js +35 -0
  28. package/dist/server/models/chan.js +275 -0
  29. package/dist/server/models/msg.js +92 -0
  30. package/dist/server/models/network.js +546 -0
  31. package/dist/server/models/prefix.js +31 -0
  32. package/dist/server/models/user.js +42 -0
  33. package/dist/server/plugins/auth/ldap.js +188 -0
  34. package/dist/server/plugins/auth/local.js +41 -0
  35. package/dist/server/plugins/auth.js +70 -0
  36. package/dist/server/plugins/changelog.js +103 -0
  37. package/dist/server/plugins/clientCertificate.js +115 -0
  38. package/dist/server/plugins/dev-server.js +33 -0
  39. package/dist/server/plugins/inputs/action.js +54 -0
  40. package/dist/server/plugins/inputs/away.js +20 -0
  41. package/dist/server/plugins/inputs/ban.js +45 -0
  42. package/dist/server/plugins/inputs/blow.js +44 -0
  43. package/dist/server/plugins/inputs/connect.js +41 -0
  44. package/dist/server/plugins/inputs/ctcp.js +29 -0
  45. package/dist/server/plugins/inputs/disconnect.js +15 -0
  46. package/dist/server/plugins/inputs/ignore.js +74 -0
  47. package/dist/server/plugins/inputs/ignorelist.js +50 -0
  48. package/dist/server/plugins/inputs/index.js +105 -0
  49. package/dist/server/plugins/inputs/invite.js +31 -0
  50. package/dist/server/plugins/inputs/kick.js +26 -0
  51. package/dist/server/plugins/inputs/kill.js +13 -0
  52. package/dist/server/plugins/inputs/list.js +12 -0
  53. package/dist/server/plugins/inputs/mode.js +55 -0
  54. package/dist/server/plugins/inputs/msg.js +106 -0
  55. package/dist/server/plugins/inputs/mute.js +56 -0
  56. package/dist/server/plugins/inputs/nick.js +55 -0
  57. package/dist/server/plugins/inputs/notice.js +42 -0
  58. package/dist/server/plugins/inputs/part.js +46 -0
  59. package/dist/server/plugins/inputs/quit.js +27 -0
  60. package/dist/server/plugins/inputs/raw.js +13 -0
  61. package/dist/server/plugins/inputs/rejoin.js +25 -0
  62. package/dist/server/plugins/inputs/topic.js +24 -0
  63. package/dist/server/plugins/inputs/whois.js +19 -0
  64. package/dist/server/plugins/irc-events/away.js +59 -0
  65. package/dist/server/plugins/irc-events/cap.js +62 -0
  66. package/dist/server/plugins/irc-events/chghost.js +29 -0
  67. package/dist/server/plugins/irc-events/connection.js +152 -0
  68. package/dist/server/plugins/irc-events/ctcp.js +72 -0
  69. package/dist/server/plugins/irc-events/error.js +80 -0
  70. package/dist/server/plugins/irc-events/help.js +21 -0
  71. package/dist/server/plugins/irc-events/info.js +21 -0
  72. package/dist/server/plugins/irc-events/invite.js +27 -0
  73. package/dist/server/plugins/irc-events/join.js +53 -0
  74. package/dist/server/plugins/irc-events/kick.js +39 -0
  75. package/dist/server/plugins/irc-events/link.js +442 -0
  76. package/dist/server/plugins/irc-events/list.js +47 -0
  77. package/dist/server/plugins/irc-events/message.js +187 -0
  78. package/dist/server/plugins/irc-events/mode.js +124 -0
  79. package/dist/server/plugins/irc-events/modelist.js +67 -0
  80. package/dist/server/plugins/irc-events/motd.js +29 -0
  81. package/dist/server/plugins/irc-events/names.js +21 -0
  82. package/dist/server/plugins/irc-events/nick.js +45 -0
  83. package/dist/server/plugins/irc-events/part.js +35 -0
  84. package/dist/server/plugins/irc-events/quit.js +32 -0
  85. package/dist/server/plugins/irc-events/sasl.js +26 -0
  86. package/dist/server/plugins/irc-events/topic.js +42 -0
  87. package/dist/server/plugins/irc-events/unhandled.js +31 -0
  88. package/dist/server/plugins/irc-events/welcome.js +22 -0
  89. package/dist/server/plugins/irc-events/whois.js +57 -0
  90. package/dist/server/plugins/messageStorage/sqlite.js +454 -0
  91. package/dist/server/plugins/messageStorage/text.js +124 -0
  92. package/dist/server/plugins/packages/index.js +200 -0
  93. package/dist/server/plugins/packages/publicClient.js +66 -0
  94. package/dist/server/plugins/packages/themes.js +61 -0
  95. package/dist/server/plugins/storage.js +88 -0
  96. package/dist/server/plugins/sts.js +85 -0
  97. package/dist/server/plugins/uploader.js +267 -0
  98. package/dist/server/plugins/webpush.js +99 -0
  99. package/dist/server/server.js +857 -0
  100. package/dist/server/storageCleaner.js +131 -0
  101. package/dist/server/utils/fish.js +432 -0
  102. package/dist/shared/irc.js +19 -0
  103. package/dist/shared/linkify.js +81 -0
  104. package/dist/shared/types/chan.js +22 -0
  105. package/dist/shared/types/changelog.js +2 -0
  106. package/dist/shared/types/config.js +2 -0
  107. package/dist/shared/types/mention.js +2 -0
  108. package/dist/shared/types/msg.js +34 -0
  109. package/dist/shared/types/network.js +2 -0
  110. package/dist/shared/types/storage.js +2 -0
  111. package/dist/shared/types/user.js +2 -0
  112. package/dist/webpack.config.js +224 -0
  113. package/index.js +38 -0
  114. package/package.json +174 -0
  115. package/public/audio/pop.wav +0 -0
  116. package/public/css/style.css +12 -0
  117. package/public/css/style.css.map +1 -0
  118. package/public/favicon.ico +0 -0
  119. package/public/fonts/fa-solid-900.woff +0 -0
  120. package/public/fonts/fa-solid-900.woff2 +0 -0
  121. package/public/img/favicon-alerted.ico +0 -0
  122. package/public/img/icon-alerted-black-transparent-bg-72x72px.png +0 -0
  123. package/public/img/icon-alerted-grey-bg-192x192px.png +0 -0
  124. package/public/img/icon-black-transparent-bg.svg +1 -0
  125. package/public/img/logo-grey-bg-120x120px.png +0 -0
  126. package/public/img/logo-grey-bg-152x152px.png +0 -0
  127. package/public/img/logo-grey-bg-167x167px.png +0 -0
  128. package/public/img/logo-grey-bg-180x180px.png +0 -0
  129. package/public/img/logo-grey-bg-192x192px.png +0 -0
  130. package/public/img/logo-grey-bg-512x512px.png +0 -0
  131. package/public/img/logo-grey-bg.svg +1 -0
  132. package/public/img/logo-horizontal-transparent-bg-inverted.svg +1 -0
  133. package/public/img/logo-horizontal-transparent-bg.svg +1 -0
  134. package/public/img/logo-transparent-bg-inverted.svg +1 -0
  135. package/public/img/logo-transparent-bg.svg +1 -0
  136. package/public/img/logo-vertical-transparent-bg-inverted.svg +1 -0
  137. package/public/img/logo-vertical-transparent-bg.svg +1 -0
  138. package/public/js/bundle.js +2 -0
  139. package/public/js/bundle.js.map +1 -0
  140. package/public/js/bundle.vendor.js +3 -0
  141. package/public/js/bundle.vendor.js.LICENSE.txt +18 -0
  142. package/public/js/bundle.vendor.js.map +1 -0
  143. package/public/js/loading-error-handlers.js +1 -0
  144. package/public/robots.txt +2 -0
  145. package/public/service-worker.js +1 -0
  146. package/public/thelounge.webmanifest +53 -0
  147. package/public/themes/default.css +35 -0
  148. package/public/themes/morning.css +183 -0
@@ -0,0 +1,200 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const lodash_1 = __importDefault(require("lodash"));
7
+ const log_1 = __importDefault(require("../../log"));
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const semver_1 = __importDefault(require("semver"));
11
+ const helper_1 = __importDefault(require("../../helper"));
12
+ const config_1 = __importDefault(require("../../config"));
13
+ const themes_1 = __importDefault(require("./themes"));
14
+ const inputs_1 = __importDefault(require("../inputs"));
15
+ const fs_1 = __importDefault(require("fs"));
16
+ const utils_1 = __importDefault(require("../../command-line/utils"));
17
+ const packageMap = new Map();
18
+ const stylesheets = [];
19
+ const files = [];
20
+ const TIME_TO_LIVE = 15 * 60 * 1000; // 15 minutes, in milliseconds
21
+ const cache = {
22
+ outdated: undefined,
23
+ };
24
+ let experimentalWarningPrinted = false;
25
+ exports.default = {
26
+ getFiles,
27
+ getStylesheets,
28
+ getPackage,
29
+ loadPackages,
30
+ outdated,
31
+ };
32
+ // TODO: verify binds worked. Used to be 'this' instead of 'packageApis'
33
+ const packageApis = function (packageInfo) {
34
+ return {
35
+ Stylesheets: {
36
+ addFile: addStylesheet.bind(packageApis, packageInfo.packageName),
37
+ },
38
+ PublicFiles: {
39
+ add: addFile.bind(packageApis, packageInfo.packageName),
40
+ },
41
+ Commands: {
42
+ add: inputs_1.default.addPluginCommand.bind(packageApis, packageInfo),
43
+ runAsUser: (command, targetId, client) => client.inputLine({ target: targetId, text: command }),
44
+ },
45
+ Config: {
46
+ getConfig: () => config_1.default.values,
47
+ getPersistentStorageDir: getPersistentStorageDir.bind(packageApis, packageInfo.packageName),
48
+ },
49
+ Logger: {
50
+ error: (...args) => log_1.default.error(`[${packageInfo.packageName}]`, ...args),
51
+ warn: (...args) => log_1.default.warn(`[${packageInfo.packageName}]`, ...args),
52
+ info: (...args) => log_1.default.info(`[${packageInfo.packageName}]`, ...args),
53
+ debug: (...args) => log_1.default.debug(`[${packageInfo.packageName}]`, ...args),
54
+ },
55
+ };
56
+ };
57
+ function addStylesheet(packageName, filename) {
58
+ stylesheets.push(packageName + "/" + filename);
59
+ }
60
+ function getStylesheets() {
61
+ return stylesheets;
62
+ }
63
+ function addFile(packageName, filename) {
64
+ files.push(packageName + "/" + filename);
65
+ }
66
+ function getFiles() {
67
+ return files.concat(stylesheets);
68
+ }
69
+ function getPackage(name) {
70
+ return packageMap.get(name);
71
+ }
72
+ function getEnabledPackages(packageJson) {
73
+ try {
74
+ const json = JSON.parse(fs_1.default.readFileSync(packageJson, "utf-8"));
75
+ return Object.keys(json.dependencies);
76
+ }
77
+ catch (e) {
78
+ log_1.default.error(`Failed to read packages/package.json: ${chalk_1.default.red(e)}`);
79
+ }
80
+ return [];
81
+ }
82
+ function getPersistentStorageDir(packageName) {
83
+ const dir = path_1.default.join(config_1.default.getPackagesPath(), packageName);
84
+ fs_1.default.mkdirSync(dir, { recursive: true }); // we don't care if it already exists or not
85
+ return dir;
86
+ }
87
+ function loadPackage(packageName) {
88
+ let packageInfo;
89
+ // TODO: type
90
+ let packageFile;
91
+ try {
92
+ const packagePath = config_1.default.getPackageModulePath(packageName);
93
+ packageInfo = JSON.parse(fs_1.default.readFileSync(path_1.default.join(packagePath, "package.json"), "utf-8"));
94
+ if (!packageInfo.thelounge) {
95
+ throw "'thelounge' is not present in package.json";
96
+ }
97
+ if (packageInfo.thelounge.supports &&
98
+ !semver_1.default.satisfies(helper_1.default.getVersionNumber(), packageInfo.thelounge.supports, {
99
+ includePrerelease: true, // our pre-releases should respect the semver guarantees
100
+ })) {
101
+ throw `v${packageInfo.version} does not support this version of The Lounge. Supports: ${packageInfo.thelounge.supports}`;
102
+ }
103
+ packageFile = require(packagePath);
104
+ }
105
+ catch (e) {
106
+ log_1.default.error(`Package ${chalk_1.default.bold(packageName)} could not be loaded: ${chalk_1.default.red(e)}`);
107
+ if (e instanceof Error) {
108
+ log_1.default.debug(e.stack ? e.stack : e.message);
109
+ }
110
+ return;
111
+ }
112
+ const version = packageInfo.version;
113
+ packageInfo = {
114
+ ...packageInfo.thelounge,
115
+ packageName: packageName,
116
+ version,
117
+ };
118
+ packageMap.set(packageName, packageFile);
119
+ if (packageInfo.type === "theme") {
120
+ // @ts-expect-error Argument of type 'PackageInfo' is not assignable to parameter of type 'ThemeModule'.
121
+ themes_1.default.addTheme(packageName, packageInfo);
122
+ if (packageInfo.files) {
123
+ packageInfo.files.forEach((file) => addFile(packageName, file));
124
+ }
125
+ }
126
+ if (packageFile.onServerStart) {
127
+ packageFile.onServerStart(packageApis(packageInfo));
128
+ }
129
+ log_1.default.info(`Package ${chalk_1.default.bold(packageName)} ${chalk_1.default.green("v" + version)} loaded`);
130
+ if (packageInfo.type !== "theme" && !experimentalWarningPrinted) {
131
+ experimentalWarningPrinted = true;
132
+ log_1.default.info("There are packages using the experimental plugin API. " +
133
+ "Be aware that this API is not yet stable and may change in future The Lounge releases.");
134
+ }
135
+ }
136
+ function loadPackages() {
137
+ const packageJson = path_1.default.join(config_1.default.getPackagesPath(), "package.json");
138
+ const packages = getEnabledPackages(packageJson);
139
+ packages.forEach(loadPackage);
140
+ watchPackages(packageJson);
141
+ }
142
+ function watchPackages(packageJson) {
143
+ fs_1.default.watch(packageJson, {
144
+ persistent: false,
145
+ }, lodash_1.default.debounce(() => {
146
+ const updated = getEnabledPackages(packageJson);
147
+ for (const packageName of updated) {
148
+ if (packageMap.has(packageName)) {
149
+ continue;
150
+ }
151
+ loadPackage(packageName);
152
+ }
153
+ }, 1000, { maxWait: 10000 }));
154
+ }
155
+ async function outdated(cacheTimeout = TIME_TO_LIVE) {
156
+ if (cache.outdated !== undefined) {
157
+ return cache.outdated;
158
+ }
159
+ // Get paths to the location of packages directory
160
+ const packagesPath = config_1.default.getPackagesPath();
161
+ const packagesConfig = path_1.default.join(packagesPath, "package.json");
162
+ const packagesList = JSON.parse(fs_1.default.readFileSync(packagesConfig, "utf-8")).dependencies;
163
+ const argsList = [
164
+ "outdated",
165
+ "--latest",
166
+ "--json",
167
+ "--production",
168
+ "--ignore-scripts",
169
+ "--non-interactive",
170
+ "--cwd",
171
+ packagesPath,
172
+ ];
173
+ // Check if the configuration file exists
174
+ if (!Object.entries(packagesList).length) {
175
+ // CLI calls outdated with zero TTL, so we can print the warning there
176
+ if (!cacheTimeout) {
177
+ log_1.default.warn("There are no packages installed.");
178
+ }
179
+ return false;
180
+ }
181
+ const command = argsList.shift();
182
+ const params = argsList;
183
+ if (!command) {
184
+ return;
185
+ }
186
+ // If we get an error from calling outdated and the code isn't 0, then there are no outdated packages
187
+ // TODO: was (...argsList), verify this works
188
+ await utils_1.default.executeYarnCommand(command, ...params)
189
+ .then(() => updateOutdated(false))
190
+ .catch((code) => updateOutdated(code !== 0));
191
+ if (cacheTimeout > 0) {
192
+ setTimeout(() => {
193
+ delete cache.outdated;
194
+ }, cacheTimeout);
195
+ }
196
+ return cache.outdated;
197
+ }
198
+ function updateOutdated(outdatedPackages) {
199
+ cache.outdated = outdatedPackages;
200
+ }
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const msg_1 = __importDefault(require("../../models/msg"));
7
+ const msg_2 = require("../../../shared/types/msg");
8
+ class PublicClient {
9
+ client;
10
+ packageInfo;
11
+ constructor(client, packageInfo) {
12
+ this.client = client;
13
+ this.packageInfo = packageInfo;
14
+ }
15
+ /**
16
+ *
17
+ * @param {String} command - IRC command to run, this is in the same format that a client would send to the server (eg: JOIN #test)
18
+ * @param {String} targetId - The id of the channel to simulate the command coming from. Replies will go to this channel if appropriate
19
+ */
20
+ runAsUser(command, targetId) {
21
+ this.client.inputLine({ target: targetId, text: command });
22
+ }
23
+ /**
24
+ *
25
+ * @param {Object} attributes
26
+ */
27
+ createChannel(attributes) {
28
+ return this.client.createChannel(attributes);
29
+ }
30
+ /**
31
+ * Emits an `event` to the browser client, with `data` in the body of the event.
32
+ *
33
+ * @param {String} event - Name of the event, must be something the browser will recognise
34
+ * @param {Object} data - Body of the event, can be anything, but will need to be properly interpreted by the client
35
+ */
36
+ // FIXME: this is utterly bonkers
37
+ // This needs to get wrapped into its own, typed plugin event
38
+ // Plus it is completely insane to let a plugin inject arbitrary events like that
39
+ sendToBrowser(event, data) {
40
+ this.client.emit(event, data);
41
+ }
42
+ /**
43
+ *
44
+ * @param {Number} chanId
45
+ */
46
+ getChannel(chanId) {
47
+ return this.client.find(chanId);
48
+ }
49
+ /**
50
+ * Sends a message to this client, displayed in the given channel.
51
+ *
52
+ * @param {String} text the message to send
53
+ * @param {Chan} chan the channel to send the message to
54
+ */
55
+ sendMessage(text, chan) {
56
+ chan.pushMessage(this.client, new msg_1.default({
57
+ type: msg_2.MessageType.PLUGIN,
58
+ text: text,
59
+ from: {
60
+ nick: this.packageInfo.name || this.packageInfo.packageName,
61
+ mode: "",
62
+ },
63
+ }));
64
+ }
65
+ }
66
+ exports.default = PublicClient;
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const fs_1 = __importDefault(require("fs"));
7
+ const path_1 = __importDefault(require("path"));
8
+ const lodash_1 = __importDefault(require("lodash"));
9
+ const config_1 = __importDefault(require("../../config"));
10
+ const utils_1 = __importDefault(require("../../command-line/utils"));
11
+ const themes = new Map();
12
+ exports.default = {
13
+ addTheme,
14
+ getAll,
15
+ getByName,
16
+ loadLocalThemes,
17
+ };
18
+ function loadLocalThemes() {
19
+ const builtInThemes = fs_1.default.readdirSync(utils_1.default.getFileFromRelativeToRoot("public", "themes"));
20
+ builtInThemes
21
+ .filter((theme) => theme.endsWith(".css"))
22
+ .map(makeLocalThemeObject)
23
+ .forEach((theme) => themes.set(theme.name, theme));
24
+ }
25
+ function addTheme(packageName, packageObject) {
26
+ const theme = makePackageThemeObject(packageName, packageObject);
27
+ if (theme) {
28
+ themes.set(theme.name, theme);
29
+ }
30
+ }
31
+ function getAll() {
32
+ const filteredThemes = [];
33
+ for (const theme of themes.values()) {
34
+ filteredThemes.push(lodash_1.default.pick(theme, ["displayName", "name", "themeColor"]));
35
+ }
36
+ return lodash_1.default.sortBy(filteredThemes, "displayName");
37
+ }
38
+ function getByName(name) {
39
+ return themes.get(name);
40
+ }
41
+ function makeLocalThemeObject(css) {
42
+ const themeName = css.slice(0, -4);
43
+ return {
44
+ displayName: themeName.charAt(0).toUpperCase() + themeName.slice(1),
45
+ name: themeName,
46
+ themeColor: null,
47
+ };
48
+ }
49
+ function makePackageThemeObject(moduleName, module) {
50
+ if (!module || module.type !== "theme") {
51
+ return;
52
+ }
53
+ const themeColor = /^#[0-9A-F]{6}$/i.test(module.themeColor) ? module.themeColor : null;
54
+ const modulePath = config_1.default.getPackageModulePath(moduleName);
55
+ return {
56
+ displayName: module.name || moduleName,
57
+ filename: path_1.default.join(modulePath, module.css),
58
+ name: encodeURIComponent(moduleName),
59
+ themeColor: themeColor,
60
+ };
61
+ }
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const log_1 = __importDefault(require("../log"));
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const crypto_1 = __importDefault(require("crypto"));
10
+ const config_1 = __importDefault(require("../config"));
11
+ class Storage {
12
+ references;
13
+ constructor() {
14
+ this.references = new Map();
15
+ }
16
+ emptyDir() {
17
+ // Ensures that a directory is empty.
18
+ // Deletes directory contents if the directory is not empty.
19
+ // If the directory does not exist, it is created.
20
+ const dir = config_1.default.getStoragePath();
21
+ let items;
22
+ try {
23
+ items = fs_1.default.readdirSync(dir);
24
+ }
25
+ catch (e) {
26
+ fs_1.default.mkdirSync(dir, { recursive: true });
27
+ return;
28
+ }
29
+ // TODO: Use `fs.rmdirSync(dir, {recursive: true});` when it's stable (node 13+)
30
+ items.forEach((item) => deleteFolder(path_1.default.join(dir, item)));
31
+ }
32
+ dereference(url) {
33
+ const references = (this.references.get(url) || 0) - 1;
34
+ if (references < 0) {
35
+ return log_1.default.warn("Tried to dereference a file that has no references", url);
36
+ }
37
+ if (references > 0) {
38
+ return this.references.set(url, references);
39
+ }
40
+ this.references.delete(url);
41
+ // Drop "storage/" from url and join it with full storage path
42
+ const filePath = path_1.default.join(config_1.default.getStoragePath(), url.substring(8));
43
+ fs_1.default.unlink(filePath, (err) => {
44
+ if (err) {
45
+ log_1.default.error("Failed to delete stored file", err.message);
46
+ }
47
+ });
48
+ }
49
+ store(data, extension, callback) {
50
+ const hash = crypto_1.default.createHash("sha256").update(data).digest("hex");
51
+ const a = hash.substring(0, 2);
52
+ const b = hash.substring(2, 4);
53
+ const folder = path_1.default.join(config_1.default.getStoragePath(), a, b);
54
+ const filePath = path_1.default.join(folder, `${hash.substring(4)}.${extension}`);
55
+ const url = `storage/${a}/${b}/${hash.substring(4)}.${extension}`;
56
+ this.references.set(url, 1 + (this.references.get(url) || 0));
57
+ // If file with this name already exists, we don't need to write it again
58
+ if (fs_1.default.existsSync(filePath)) {
59
+ return callback(url);
60
+ }
61
+ fs_1.default.mkdir(folder, { recursive: true }, (mkdirErr) => {
62
+ if (mkdirErr) {
63
+ log_1.default.error("Failed to create storage folder", mkdirErr.message);
64
+ return callback("");
65
+ }
66
+ fs_1.default.writeFile(filePath, data, (err) => {
67
+ if (err) {
68
+ log_1.default.error("Failed to store a file", err.message);
69
+ return callback("");
70
+ }
71
+ callback(url);
72
+ });
73
+ });
74
+ }
75
+ }
76
+ exports.default = new Storage();
77
+ function deleteFolder(dir) {
78
+ fs_1.default.readdirSync(dir).forEach((item) => {
79
+ item = path_1.default.join(dir, item);
80
+ if (fs_1.default.lstatSync(item).isDirectory()) {
81
+ deleteFolder(item);
82
+ }
83
+ else {
84
+ fs_1.default.unlinkSync(item);
85
+ }
86
+ });
87
+ fs_1.default.rmdirSync(dir);
88
+ }
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const lodash_1 = __importDefault(require("lodash"));
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const log_1 = __importDefault(require("../log"));
10
+ const config_1 = __importDefault(require("../config"));
11
+ class STSPolicies {
12
+ stsFile;
13
+ refresh;
14
+ policies;
15
+ constructor() {
16
+ this.stsFile = path_1.default.join(config_1.default.getHomePath(), "sts-policies.json");
17
+ this.policies = new Map();
18
+ // eslint-disable-next-line @typescript-eslint/unbound-method
19
+ this.refresh = lodash_1.default.debounce(this.saveFile, 10000, { maxWait: 60000 });
20
+ if (!fs_1.default.existsSync(this.stsFile)) {
21
+ return;
22
+ }
23
+ const storedPolicies = JSON.parse(fs_1.default.readFileSync(this.stsFile, "utf-8"));
24
+ const now = Date.now();
25
+ storedPolicies.forEach((value) => {
26
+ if (value.expires > now) {
27
+ this.policies.set(value.host, {
28
+ port: value.port,
29
+ duration: value.duration,
30
+ expires: value.expires,
31
+ });
32
+ }
33
+ });
34
+ }
35
+ get(host) {
36
+ const policy = this.policies.get(host);
37
+ if (typeof policy === "undefined") {
38
+ return null;
39
+ }
40
+ if (policy.expires <= Date.now()) {
41
+ this.policies.delete(host);
42
+ this.refresh();
43
+ return null;
44
+ }
45
+ return policy;
46
+ }
47
+ update(host, port, duration) {
48
+ if (duration > 0) {
49
+ this.policies.set(host, {
50
+ port: port,
51
+ duration: duration,
52
+ expires: Date.now() + duration * 1000,
53
+ });
54
+ }
55
+ else {
56
+ this.policies.delete(host);
57
+ }
58
+ this.refresh();
59
+ }
60
+ refreshExpiration(host) {
61
+ const policy = this.policies.get(host);
62
+ if (typeof policy === "undefined") {
63
+ return null;
64
+ }
65
+ policy.expires = Date.now() + policy.duration * 1000;
66
+ }
67
+ saveFile() {
68
+ const policiesToStore = [];
69
+ this.policies.forEach((value, key) => {
70
+ policiesToStore.push({
71
+ host: key,
72
+ port: value.port,
73
+ duration: value.duration,
74
+ expires: value.expires,
75
+ });
76
+ });
77
+ const file = JSON.stringify(policiesToStore, null, "\t");
78
+ fs_1.default.writeFile(this.stsFile, file, { flag: "w+" }, (err) => {
79
+ if (err) {
80
+ log_1.default.error("Failed to update STS policies file!", err.message);
81
+ }
82
+ });
83
+ }
84
+ }
85
+ exports.default = new STSPolicies();