strapi-plugin-magic-mail 2.1.0 → 2.2.2
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.
- package/README.md +2 -0
- package/dist/server/index.js +431 -353
- package/dist/server/index.mjs +431 -353
- package/package.json +1 -1
- package/server/src/bootstrap.js +36 -32
- package/server/src/config/index.js +4 -1
- package/server/src/destroy.js +8 -4
- package/server/src/services/license-guard.js +44 -39
- package/server/src/utils/logger.js +84 -0
package/dist/server/index.js
CHANGED
|
@@ -25,29 +25,98 @@ function requireRegister() {
|
|
|
25
25
|
};
|
|
26
26
|
return register;
|
|
27
27
|
}
|
|
28
|
+
var logger;
|
|
29
|
+
var hasRequiredLogger;
|
|
30
|
+
function requireLogger() {
|
|
31
|
+
if (hasRequiredLogger) return logger;
|
|
32
|
+
hasRequiredLogger = 1;
|
|
33
|
+
const PLUGIN_NAME = "magic-mail";
|
|
34
|
+
const PREFIX = "[magic-mail]";
|
|
35
|
+
function formatMessage(prefix, args) {
|
|
36
|
+
if (args.length === 0) return prefix;
|
|
37
|
+
const parts = args.map(
|
|
38
|
+
(arg) => typeof arg === "string" ? arg : JSON.stringify(arg)
|
|
39
|
+
);
|
|
40
|
+
return `${prefix} ${parts.join(" ")}`;
|
|
41
|
+
}
|
|
42
|
+
function createLogger(strapi2) {
|
|
43
|
+
const getDebugMode = () => {
|
|
44
|
+
try {
|
|
45
|
+
const config2 = strapi2.config.get(`plugin::${PLUGIN_NAME}`) || {};
|
|
46
|
+
return config2.debug === true;
|
|
47
|
+
} catch {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
return {
|
|
52
|
+
/**
|
|
53
|
+
* Log info - only when debug: true
|
|
54
|
+
*/
|
|
55
|
+
info: (...args) => {
|
|
56
|
+
if (getDebugMode()) {
|
|
57
|
+
strapi2.log.info(formatMessage(PREFIX, args));
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
/**
|
|
61
|
+
* Log debug - only when debug: true
|
|
62
|
+
*/
|
|
63
|
+
debug: (...args) => {
|
|
64
|
+
if (getDebugMode()) {
|
|
65
|
+
strapi2.log.debug(formatMessage(PREFIX, args));
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
/**
|
|
69
|
+
* Log warning - only when debug: true
|
|
70
|
+
*/
|
|
71
|
+
warn: (...args) => {
|
|
72
|
+
if (getDebugMode()) {
|
|
73
|
+
strapi2.log.warn(formatMessage(PREFIX, args));
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
/**
|
|
77
|
+
* Log error - only when debug: true
|
|
78
|
+
*/
|
|
79
|
+
error: (...args) => {
|
|
80
|
+
if (getDebugMode()) {
|
|
81
|
+
strapi2.log.error(formatMessage(PREFIX, args));
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
/**
|
|
85
|
+
* Force log - always logged (for critical errors only)
|
|
86
|
+
*/
|
|
87
|
+
forceError: (...args) => {
|
|
88
|
+
strapi2.log.error(formatMessage(PREFIX, args));
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
logger = { createLogger };
|
|
93
|
+
return logger;
|
|
94
|
+
}
|
|
28
95
|
var bootstrap;
|
|
29
96
|
var hasRequiredBootstrap;
|
|
30
97
|
function requireBootstrap() {
|
|
31
98
|
if (hasRequiredBootstrap) return bootstrap;
|
|
32
99
|
hasRequiredBootstrap = 1;
|
|
100
|
+
const { createLogger } = requireLogger();
|
|
33
101
|
bootstrap = async ({ strapi: strapi2 }) => {
|
|
34
|
-
|
|
102
|
+
const log = createLogger(strapi2);
|
|
103
|
+
log.info("[BOOTSTRAP] Starting...");
|
|
35
104
|
try {
|
|
36
105
|
const licenseGuardService = strapi2.plugin("magic-mail").service("license-guard");
|
|
37
106
|
setTimeout(async () => {
|
|
38
107
|
const licenseStatus = await licenseGuardService.initialize();
|
|
39
108
|
if (!licenseStatus.valid && licenseStatus.demo) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
109
|
+
log.error("╔════════════════════════════════════════════════════════════════╗");
|
|
110
|
+
log.error("║ [ERROR] MAGICMAIL - NO VALID LICENSE ║");
|
|
111
|
+
log.error("║ ║");
|
|
112
|
+
log.error("║ This plugin requires a valid license to operate. ║");
|
|
113
|
+
log.error("║ Please activate your license via Admin UI: ║");
|
|
114
|
+
log.error("║ Go to MagicMail → License tab ║");
|
|
115
|
+
log.error("║ ║");
|
|
116
|
+
log.error('║ Click "Generate Free License" to get started! ║');
|
|
117
|
+
log.error("╚════════════════════════════════════════════════════════════════╝");
|
|
49
118
|
} else if (licenseStatus.gracePeriod) {
|
|
50
|
-
|
|
119
|
+
log.warn("[WARNING] Running on grace period (license server unreachable)");
|
|
51
120
|
}
|
|
52
121
|
}, 2e3);
|
|
53
122
|
const accountManager2 = strapi2.plugin("magic-mail").service("account-manager");
|
|
@@ -56,8 +125,8 @@ function requireBootstrap() {
|
|
|
56
125
|
if (originalEmailService && originalEmailService.send) {
|
|
57
126
|
const originalSend = originalEmailService.send.bind(originalEmailService);
|
|
58
127
|
originalEmailService.send = async (emailData) => {
|
|
59
|
-
|
|
60
|
-
|
|
128
|
+
log.info("[EMAIL] Intercepted from native Strapi service");
|
|
129
|
+
log.debug("Email data:", {
|
|
61
130
|
to: emailData.to,
|
|
62
131
|
subject: emailData.subject,
|
|
63
132
|
templateId: emailData.templateId,
|
|
@@ -69,31 +138,31 @@ function requireBootstrap() {
|
|
|
69
138
|
emailData.templateData = emailData.data;
|
|
70
139
|
}
|
|
71
140
|
const result = await emailRouter2.send(emailData);
|
|
72
|
-
|
|
141
|
+
log.info("[SUCCESS] Email routed successfully through MagicMail");
|
|
73
142
|
return result;
|
|
74
143
|
} catch (magicMailError) {
|
|
75
|
-
|
|
76
|
-
|
|
144
|
+
log.warn("[WARNING] MagicMail routing failed, falling back to original service");
|
|
145
|
+
log.error("Error:", magicMailError.message);
|
|
77
146
|
return await originalSend(emailData);
|
|
78
147
|
}
|
|
79
148
|
};
|
|
80
|
-
|
|
81
|
-
|
|
149
|
+
log.info("[SUCCESS] Native email service overridden!");
|
|
150
|
+
log.info("[INFO] All strapi.plugins.email.services.email.send() calls will route through MagicMail");
|
|
82
151
|
} else {
|
|
83
|
-
|
|
84
|
-
|
|
152
|
+
log.warn("[WARNING] Native email service not found - MagicMail will work standalone");
|
|
153
|
+
log.warn("[INFO] Make sure @strapi/plugin-email is installed");
|
|
85
154
|
}
|
|
86
155
|
const hourlyResetInterval = setInterval(async () => {
|
|
87
156
|
try {
|
|
88
157
|
if (!strapi2 || !strapi2.plugin) {
|
|
89
|
-
console.warn("
|
|
158
|
+
console.warn("Strapi not available for hourly reset");
|
|
90
159
|
return;
|
|
91
160
|
}
|
|
92
161
|
const accountMgr = strapi2.plugin("magic-mail").service("account-manager");
|
|
93
162
|
await accountMgr.resetCounters("hourly");
|
|
94
|
-
|
|
163
|
+
log.info("[RESET] Hourly counters reset");
|
|
95
164
|
} catch (err) {
|
|
96
|
-
console.error("
|
|
165
|
+
console.error("Hourly reset error:", err.message);
|
|
97
166
|
}
|
|
98
167
|
}, 60 * 60 * 1e3);
|
|
99
168
|
if (!commonjsGlobal.magicMailIntervals) commonjsGlobal.magicMailIntervals = {};
|
|
@@ -104,34 +173,34 @@ function requireBootstrap() {
|
|
|
104
173
|
setTimeout(async () => {
|
|
105
174
|
try {
|
|
106
175
|
if (!strapi2 || !strapi2.plugin) {
|
|
107
|
-
console.warn("
|
|
176
|
+
console.warn("Strapi not available for daily reset");
|
|
108
177
|
return;
|
|
109
178
|
}
|
|
110
179
|
const accountMgr = strapi2.plugin("magic-mail").service("account-manager");
|
|
111
180
|
await accountMgr.resetCounters("daily");
|
|
112
|
-
|
|
181
|
+
log.info("[RESET] Daily counters reset");
|
|
113
182
|
const dailyResetInterval = setInterval(async () => {
|
|
114
183
|
try {
|
|
115
184
|
if (!strapi2 || !strapi2.plugin) {
|
|
116
|
-
console.warn("
|
|
185
|
+
console.warn("Strapi not available for daily reset");
|
|
117
186
|
return;
|
|
118
187
|
}
|
|
119
188
|
const accountMgr2 = strapi2.plugin("magic-mail").service("account-manager");
|
|
120
189
|
await accountMgr2.resetCounters("daily");
|
|
121
|
-
|
|
190
|
+
log.info("[RESET] Daily counters reset");
|
|
122
191
|
} catch (err) {
|
|
123
|
-
console.error("
|
|
192
|
+
console.error("Daily reset error:", err.message);
|
|
124
193
|
}
|
|
125
194
|
}, 24 * 60 * 60 * 1e3);
|
|
126
195
|
commonjsGlobal.magicMailIntervals.daily = dailyResetInterval;
|
|
127
196
|
} catch (err) {
|
|
128
|
-
console.error("
|
|
197
|
+
console.error("Initial daily reset error:", err.message);
|
|
129
198
|
}
|
|
130
199
|
}, msUntilMidnight);
|
|
131
|
-
|
|
132
|
-
|
|
200
|
+
log.info("[SUCCESS] Counter reset schedules initialized");
|
|
201
|
+
log.info("[SUCCESS] Bootstrap complete");
|
|
133
202
|
} catch (err) {
|
|
134
|
-
|
|
203
|
+
log.error("[ERROR] Bootstrap error:", err);
|
|
135
204
|
}
|
|
136
205
|
};
|
|
137
206
|
return bootstrap;
|
|
@@ -141,22 +210,24 @@ var hasRequiredDestroy;
|
|
|
141
210
|
function requireDestroy() {
|
|
142
211
|
if (hasRequiredDestroy) return destroy;
|
|
143
212
|
hasRequiredDestroy = 1;
|
|
213
|
+
const { createLogger } = requireLogger();
|
|
144
214
|
destroy = ({ strapi: strapi2 }) => {
|
|
215
|
+
const log = createLogger(strapi2);
|
|
145
216
|
if (commonjsGlobal.magicMailIntervals) {
|
|
146
217
|
if (commonjsGlobal.magicMailIntervals.hourly) {
|
|
147
218
|
clearInterval(commonjsGlobal.magicMailIntervals.hourly);
|
|
148
|
-
|
|
219
|
+
log.info("Cleared hourly reset interval");
|
|
149
220
|
}
|
|
150
221
|
if (commonjsGlobal.magicMailIntervals.daily) {
|
|
151
222
|
clearInterval(commonjsGlobal.magicMailIntervals.daily);
|
|
152
|
-
|
|
223
|
+
log.info("Cleared daily reset interval");
|
|
153
224
|
}
|
|
154
225
|
}
|
|
155
226
|
if (strapi2.licenseGuardMagicMail && strapi2.licenseGuardMagicMail.pingInterval) {
|
|
156
227
|
clearInterval(strapi2.licenseGuardMagicMail.pingInterval);
|
|
157
|
-
|
|
228
|
+
log.info("Cleared license ping interval");
|
|
158
229
|
}
|
|
159
|
-
|
|
230
|
+
log.info("👋 Plugin destroyed gracefully");
|
|
160
231
|
};
|
|
161
232
|
return destroy;
|
|
162
233
|
}
|
|
@@ -166,7 +237,10 @@ function requireConfig() {
|
|
|
166
237
|
if (hasRequiredConfig) return config;
|
|
167
238
|
hasRequiredConfig = 1;
|
|
168
239
|
config = {
|
|
169
|
-
default: {
|
|
240
|
+
default: {
|
|
241
|
+
// Enable debug logging (set to true to see all plugin logs)
|
|
242
|
+
debug: false
|
|
243
|
+
},
|
|
170
244
|
validator() {
|
|
171
245
|
}
|
|
172
246
|
};
|
|
@@ -4796,7 +4870,7 @@ function requireOauth() {
|
|
|
4796
4870
|
});
|
|
4797
4871
|
return oauth;
|
|
4798
4872
|
}
|
|
4799
|
-
const version = "2.
|
|
4873
|
+
const version = "2.2.1";
|
|
4800
4874
|
const require$$2 = {
|
|
4801
4875
|
version
|
|
4802
4876
|
};
|
|
@@ -4808,352 +4882,356 @@ function requireLicenseGuard() {
|
|
|
4808
4882
|
const crypto = require$$0__default.default;
|
|
4809
4883
|
const os = require$$1__default.default;
|
|
4810
4884
|
const pluginPkg = require$$2;
|
|
4885
|
+
const { createLogger } = requireLogger();
|
|
4811
4886
|
const LICENSE_SERVER_URL = "https://magicapi.fitlex.me";
|
|
4812
|
-
licenseGuard = ({ strapi: strapi2 }) =>
|
|
4813
|
-
|
|
4814
|
-
|
|
4815
|
-
|
|
4816
|
-
|
|
4817
|
-
|
|
4818
|
-
|
|
4819
|
-
|
|
4820
|
-
|
|
4821
|
-
|
|
4822
|
-
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
|
|
4826
|
-
|
|
4827
|
-
|
|
4828
|
-
|
|
4829
|
-
|
|
4830
|
-
|
|
4887
|
+
licenseGuard = ({ strapi: strapi2 }) => {
|
|
4888
|
+
const log = createLogger(strapi2);
|
|
4889
|
+
return {
|
|
4890
|
+
/**
|
|
4891
|
+
* Get license server URL
|
|
4892
|
+
*/
|
|
4893
|
+
getLicenseServerUrl() {
|
|
4894
|
+
return LICENSE_SERVER_URL;
|
|
4895
|
+
},
|
|
4896
|
+
/**
|
|
4897
|
+
* Generate device ID
|
|
4898
|
+
*/
|
|
4899
|
+
generateDeviceId() {
|
|
4900
|
+
try {
|
|
4901
|
+
const networkInterfaces = os.networkInterfaces();
|
|
4902
|
+
const macAddresses = [];
|
|
4903
|
+
Object.values(networkInterfaces).forEach((interfaces) => {
|
|
4904
|
+
interfaces?.forEach((iface) => {
|
|
4905
|
+
if (iface.mac && iface.mac !== "00:00:00:00:00:00") {
|
|
4906
|
+
macAddresses.push(iface.mac);
|
|
4907
|
+
}
|
|
4908
|
+
});
|
|
4831
4909
|
});
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
|
|
4835
|
-
|
|
4836
|
-
|
|
4837
|
-
}
|
|
4838
|
-
|
|
4839
|
-
|
|
4840
|
-
|
|
4841
|
-
|
|
4842
|
-
|
|
4843
|
-
|
|
4844
|
-
}
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
|
|
4848
|
-
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
|
|
4854
|
-
|
|
4910
|
+
const identifier = `${macAddresses.join("-")}-${os.hostname()}`;
|
|
4911
|
+
return crypto.createHash("sha256").update(identifier).digest("hex").substring(0, 32);
|
|
4912
|
+
} catch (error) {
|
|
4913
|
+
return crypto.randomBytes(16).toString("hex");
|
|
4914
|
+
}
|
|
4915
|
+
},
|
|
4916
|
+
getDeviceName() {
|
|
4917
|
+
try {
|
|
4918
|
+
return os.hostname() || "Unknown Device";
|
|
4919
|
+
} catch (error) {
|
|
4920
|
+
return "Unknown Device";
|
|
4921
|
+
}
|
|
4922
|
+
},
|
|
4923
|
+
getIpAddress() {
|
|
4924
|
+
try {
|
|
4925
|
+
const networkInterfaces = os.networkInterfaces();
|
|
4926
|
+
for (const name of Object.keys(networkInterfaces)) {
|
|
4927
|
+
const interfaces = networkInterfaces[name];
|
|
4928
|
+
if (interfaces) {
|
|
4929
|
+
for (const iface of interfaces) {
|
|
4930
|
+
if (iface.family === "IPv4" && !iface.internal) {
|
|
4931
|
+
return iface.address;
|
|
4932
|
+
}
|
|
4855
4933
|
}
|
|
4856
4934
|
}
|
|
4857
4935
|
}
|
|
4936
|
+
return "127.0.0.1";
|
|
4937
|
+
} catch (error) {
|
|
4938
|
+
return "127.0.0.1";
|
|
4858
4939
|
}
|
|
4859
|
-
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
4864
|
-
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
|
|
4880
|
-
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
|
|
4886
|
-
|
|
4887
|
-
|
|
4888
|
-
|
|
4889
|
-
|
|
4890
|
-
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
|
|
4895
|
-
}
|
|
4896
|
-
|
|
4940
|
+
},
|
|
4941
|
+
getUserAgent() {
|
|
4942
|
+
const pluginVersion = pluginPkg.version;
|
|
4943
|
+
const strapiVersion = strapi2.config.get("info.strapi") || "5.0.0";
|
|
4944
|
+
return `MagicMail/${pluginVersion} Strapi/${strapiVersion} Node/${process.version} ${os.platform()}/${os.release()}`;
|
|
4945
|
+
},
|
|
4946
|
+
async createLicense({ email, firstName, lastName }) {
|
|
4947
|
+
try {
|
|
4948
|
+
const deviceId = this.generateDeviceId();
|
|
4949
|
+
const deviceName = this.getDeviceName();
|
|
4950
|
+
const ipAddress = this.getIpAddress();
|
|
4951
|
+
const userAgent = this.getUserAgent();
|
|
4952
|
+
const licenseServerUrl = this.getLicenseServerUrl();
|
|
4953
|
+
const response = await fetch(`${licenseServerUrl}/api/licenses/create`, {
|
|
4954
|
+
method: "POST",
|
|
4955
|
+
headers: { "Content-Type": "application/json" },
|
|
4956
|
+
body: JSON.stringify({
|
|
4957
|
+
email,
|
|
4958
|
+
firstName,
|
|
4959
|
+
lastName,
|
|
4960
|
+
deviceName,
|
|
4961
|
+
deviceId,
|
|
4962
|
+
ipAddress,
|
|
4963
|
+
userAgent,
|
|
4964
|
+
pluginName: "magic-mail",
|
|
4965
|
+
productName: "MagicMail - Email Business Suite"
|
|
4966
|
+
})
|
|
4967
|
+
});
|
|
4968
|
+
const data = await response.json();
|
|
4969
|
+
if (data.success) {
|
|
4970
|
+
log.info("[SUCCESS] License created:", data.data.licenseKey);
|
|
4971
|
+
return data.data;
|
|
4972
|
+
} else {
|
|
4973
|
+
log.error("[ERROR] License creation failed:", data);
|
|
4974
|
+
return null;
|
|
4975
|
+
}
|
|
4976
|
+
} catch (error) {
|
|
4977
|
+
log.error("[ERROR] Error creating license:", error);
|
|
4897
4978
|
return null;
|
|
4898
4979
|
}
|
|
4899
|
-
}
|
|
4900
|
-
|
|
4901
|
-
|
|
4902
|
-
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
|
|
4906
|
-
|
|
4907
|
-
|
|
4908
|
-
|
|
4909
|
-
|
|
4910
|
-
|
|
4911
|
-
|
|
4912
|
-
|
|
4913
|
-
|
|
4914
|
-
|
|
4915
|
-
|
|
4916
|
-
|
|
4917
|
-
|
|
4918
|
-
|
|
4919
|
-
|
|
4920
|
-
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
|
|
4980
|
+
},
|
|
4981
|
+
async verifyLicense(licenseKey, allowGracePeriod = false) {
|
|
4982
|
+
try {
|
|
4983
|
+
const controller2 = new AbortController();
|
|
4984
|
+
const timeoutId = setTimeout(() => controller2.abort(), 5e3);
|
|
4985
|
+
const licenseServerUrl = this.getLicenseServerUrl();
|
|
4986
|
+
const response = await fetch(`${licenseServerUrl}/api/licenses/verify`, {
|
|
4987
|
+
method: "POST",
|
|
4988
|
+
headers: { "Content-Type": "application/json" },
|
|
4989
|
+
body: JSON.stringify({
|
|
4990
|
+
licenseKey,
|
|
4991
|
+
pluginName: "magic-mail",
|
|
4992
|
+
productName: "MagicMail - Email Business Suite"
|
|
4993
|
+
}),
|
|
4994
|
+
signal: controller2.signal
|
|
4995
|
+
});
|
|
4996
|
+
clearTimeout(timeoutId);
|
|
4997
|
+
const data = await response.json();
|
|
4998
|
+
if (data.success && data.data) {
|
|
4999
|
+
return { valid: true, data: data.data, gracePeriod: false };
|
|
5000
|
+
} else {
|
|
5001
|
+
return { valid: false, data: null };
|
|
5002
|
+
}
|
|
5003
|
+
} catch (error) {
|
|
5004
|
+
if (allowGracePeriod) {
|
|
5005
|
+
log.warn("[WARNING] License verification timeout - grace period active");
|
|
5006
|
+
return { valid: true, data: null, gracePeriod: true };
|
|
5007
|
+
}
|
|
5008
|
+
log.error("[ERROR] License verification error:", error.message);
|
|
4924
5009
|
return { valid: false, data: null };
|
|
4925
5010
|
}
|
|
4926
|
-
}
|
|
4927
|
-
|
|
4928
|
-
|
|
4929
|
-
|
|
4930
|
-
|
|
4931
|
-
|
|
4932
|
-
|
|
4933
|
-
|
|
4934
|
-
|
|
4935
|
-
|
|
4936
|
-
|
|
4937
|
-
|
|
4938
|
-
|
|
4939
|
-
|
|
4940
|
-
|
|
4941
|
-
|
|
4942
|
-
|
|
4943
|
-
const data = await response.json();
|
|
4944
|
-
if (data.success && data.data) {
|
|
4945
|
-
return data.data;
|
|
5011
|
+
},
|
|
5012
|
+
async getLicenseByKey(licenseKey) {
|
|
5013
|
+
try {
|
|
5014
|
+
const licenseServerUrl = this.getLicenseServerUrl();
|
|
5015
|
+
const url = `${licenseServerUrl}/api/licenses/key/${licenseKey}`;
|
|
5016
|
+
const response = await fetch(url, {
|
|
5017
|
+
method: "GET",
|
|
5018
|
+
headers: { "Content-Type": "application/json" }
|
|
5019
|
+
});
|
|
5020
|
+
const data = await response.json();
|
|
5021
|
+
if (data.success && data.data) {
|
|
5022
|
+
return data.data;
|
|
5023
|
+
}
|
|
5024
|
+
return null;
|
|
5025
|
+
} catch (error) {
|
|
5026
|
+
log.error("Error fetching license by key:", error);
|
|
5027
|
+
return null;
|
|
4946
5028
|
}
|
|
4947
|
-
|
|
4948
|
-
|
|
4949
|
-
strapi2.log.error("[magic-mail] Error fetching license by key:", error);
|
|
4950
|
-
return null;
|
|
4951
|
-
}
|
|
4952
|
-
},
|
|
4953
|
-
async pingLicense(licenseKey) {
|
|
4954
|
-
try {
|
|
4955
|
-
const deviceId = this.generateDeviceId();
|
|
4956
|
-
const deviceName = this.getDeviceName();
|
|
4957
|
-
const ipAddress = this.getIpAddress();
|
|
4958
|
-
const userAgent = this.getUserAgent();
|
|
4959
|
-
const licenseServerUrl = this.getLicenseServerUrl();
|
|
4960
|
-
const response = await fetch(`${licenseServerUrl}/api/licenses/ping`, {
|
|
4961
|
-
method: "POST",
|
|
4962
|
-
headers: { "Content-Type": "application/json" },
|
|
4963
|
-
body: JSON.stringify({
|
|
4964
|
-
licenseKey,
|
|
4965
|
-
deviceId,
|
|
4966
|
-
deviceName,
|
|
4967
|
-
ipAddress,
|
|
4968
|
-
userAgent,
|
|
4969
|
-
pluginName: "magic-mail"
|
|
4970
|
-
})
|
|
4971
|
-
});
|
|
4972
|
-
const data = await response.json();
|
|
4973
|
-
return data.success ? data.data : null;
|
|
4974
|
-
} catch (error) {
|
|
4975
|
-
return null;
|
|
4976
|
-
}
|
|
4977
|
-
},
|
|
4978
|
-
async storeLicenseKey(licenseKey) {
|
|
4979
|
-
const pluginStore = strapi2.store({
|
|
4980
|
-
type: "plugin",
|
|
4981
|
-
name: "magic-mail"
|
|
4982
|
-
});
|
|
4983
|
-
await pluginStore.set({ key: "licenseKey", value: licenseKey });
|
|
4984
|
-
strapi2.log.info(`[magic-mail] [SUCCESS] License key stored: ${licenseKey.substring(0, 8)}...`);
|
|
4985
|
-
},
|
|
4986
|
-
startPinging(licenseKey, intervalMinutes = 15) {
|
|
4987
|
-
this.pingLicense(licenseKey);
|
|
4988
|
-
const interval = setInterval(async () => {
|
|
5029
|
+
},
|
|
5030
|
+
async pingLicense(licenseKey) {
|
|
4989
5031
|
try {
|
|
4990
|
-
|
|
5032
|
+
const deviceId = this.generateDeviceId();
|
|
5033
|
+
const deviceName = this.getDeviceName();
|
|
5034
|
+
const ipAddress = this.getIpAddress();
|
|
5035
|
+
const userAgent = this.getUserAgent();
|
|
5036
|
+
const licenseServerUrl = this.getLicenseServerUrl();
|
|
5037
|
+
const response = await fetch(`${licenseServerUrl}/api/licenses/ping`, {
|
|
5038
|
+
method: "POST",
|
|
5039
|
+
headers: { "Content-Type": "application/json" },
|
|
5040
|
+
body: JSON.stringify({
|
|
5041
|
+
licenseKey,
|
|
5042
|
+
deviceId,
|
|
5043
|
+
deviceName,
|
|
5044
|
+
ipAddress,
|
|
5045
|
+
userAgent,
|
|
5046
|
+
pluginName: "magic-mail"
|
|
5047
|
+
})
|
|
5048
|
+
});
|
|
5049
|
+
const data = await response.json();
|
|
5050
|
+
return data.success ? data.data : null;
|
|
4991
5051
|
} catch (error) {
|
|
4992
|
-
|
|
5052
|
+
return null;
|
|
4993
5053
|
}
|
|
4994
|
-
},
|
|
4995
|
-
|
|
4996
|
-
},
|
|
4997
|
-
/**
|
|
4998
|
-
* Get current license data from store
|
|
4999
|
-
*/
|
|
5000
|
-
async getCurrentLicense() {
|
|
5001
|
-
try {
|
|
5054
|
+
},
|
|
5055
|
+
async storeLicenseKey(licenseKey) {
|
|
5002
5056
|
const pluginStore = strapi2.store({
|
|
5003
5057
|
type: "plugin",
|
|
5004
5058
|
name: "magic-mail"
|
|
5005
5059
|
});
|
|
5006
|
-
|
|
5007
|
-
|
|
5060
|
+
await pluginStore.set({ key: "licenseKey", value: licenseKey });
|
|
5061
|
+
log.info(`[SUCCESS] License key stored: ${licenseKey.substring(0, 8)}...`);
|
|
5062
|
+
},
|
|
5063
|
+
startPinging(licenseKey, intervalMinutes = 15) {
|
|
5064
|
+
this.pingLicense(licenseKey);
|
|
5065
|
+
const interval = setInterval(async () => {
|
|
5066
|
+
try {
|
|
5067
|
+
await this.pingLicense(licenseKey);
|
|
5068
|
+
} catch (error) {
|
|
5069
|
+
console.error("Ping error:", error);
|
|
5070
|
+
}
|
|
5071
|
+
}, intervalMinutes * 60 * 1e3);
|
|
5072
|
+
return interval;
|
|
5073
|
+
},
|
|
5074
|
+
/**
|
|
5075
|
+
* Get current license data from store
|
|
5076
|
+
*/
|
|
5077
|
+
async getCurrentLicense() {
|
|
5078
|
+
try {
|
|
5079
|
+
const pluginStore = strapi2.store({
|
|
5080
|
+
type: "plugin",
|
|
5081
|
+
name: "magic-mail"
|
|
5082
|
+
});
|
|
5083
|
+
const licenseKey = await pluginStore.get({ key: "licenseKey" });
|
|
5084
|
+
if (!licenseKey) {
|
|
5085
|
+
return null;
|
|
5086
|
+
}
|
|
5087
|
+
const license2 = await this.getLicenseByKey(licenseKey);
|
|
5088
|
+
return license2;
|
|
5089
|
+
} catch (error) {
|
|
5090
|
+
log.error(`[ERROR] Error loading license:`, error);
|
|
5008
5091
|
return null;
|
|
5009
5092
|
}
|
|
5010
|
-
|
|
5011
|
-
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
|
|
5015
|
-
|
|
5016
|
-
|
|
5017
|
-
|
|
5018
|
-
|
|
5019
|
-
|
|
5020
|
-
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5031
|
-
|
|
5032
|
-
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
|
|
5046
|
-
|
|
5047
|
-
|
|
5048
|
-
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
});
|
|
5068
|
-
const licenseKey = await pluginStore.get({ key: "licenseKey" });
|
|
5069
|
-
const lastValidated = await pluginStore.get({ key: "lastValidated" });
|
|
5070
|
-
const now = /* @__PURE__ */ new Date();
|
|
5071
|
-
const gracePeriodHours = 24;
|
|
5072
|
-
let withinGracePeriod = false;
|
|
5073
|
-
if (lastValidated) {
|
|
5074
|
-
const lastValidatedDate = new Date(lastValidated);
|
|
5075
|
-
const hoursSinceValidation = (now.getTime() - lastValidatedDate.getTime()) / (1e3 * 60 * 60);
|
|
5076
|
-
withinGracePeriod = hoursSinceValidation < gracePeriodHours;
|
|
5077
|
-
}
|
|
5078
|
-
strapi2.log.info("──────────────────────────────────────────────────────────");
|
|
5079
|
-
strapi2.log.info(`📦 Plugin Store Check:`);
|
|
5080
|
-
if (licenseKey) {
|
|
5081
|
-
strapi2.log.info(` [SUCCESS] License Key found: ${licenseKey}`);
|
|
5082
|
-
strapi2.log.info(` [LICENSE] Key (short): ${licenseKey.substring(0, 10)}...`);
|
|
5093
|
+
},
|
|
5094
|
+
/**
|
|
5095
|
+
* Check if license has specific feature
|
|
5096
|
+
*/
|
|
5097
|
+
async hasFeature(featureName) {
|
|
5098
|
+
const license2 = await this.getCurrentLicense();
|
|
5099
|
+
const features2 = requireFeatures();
|
|
5100
|
+
return features2.hasFeature(license2, featureName);
|
|
5101
|
+
},
|
|
5102
|
+
/**
|
|
5103
|
+
* Check if provider is allowed
|
|
5104
|
+
*/
|
|
5105
|
+
async isProviderAllowed(provider) {
|
|
5106
|
+
const license2 = await this.getCurrentLicense();
|
|
5107
|
+
const features2 = requireFeatures();
|
|
5108
|
+
return features2.isProviderAllowed(license2, provider);
|
|
5109
|
+
},
|
|
5110
|
+
/**
|
|
5111
|
+
* Get max allowed accounts
|
|
5112
|
+
*/
|
|
5113
|
+
async getMaxAccounts() {
|
|
5114
|
+
const license2 = await this.getCurrentLicense();
|
|
5115
|
+
const features2 = requireFeatures();
|
|
5116
|
+
return features2.getMaxAccounts(license2);
|
|
5117
|
+
},
|
|
5118
|
+
/**
|
|
5119
|
+
* Get max allowed routing rules
|
|
5120
|
+
*/
|
|
5121
|
+
async getMaxRoutingRules() {
|
|
5122
|
+
const license2 = await this.getCurrentLicense();
|
|
5123
|
+
const features2 = requireFeatures();
|
|
5124
|
+
return features2.getMaxRoutingRules(license2);
|
|
5125
|
+
},
|
|
5126
|
+
/**
|
|
5127
|
+
* Get max allowed email templates
|
|
5128
|
+
*/
|
|
5129
|
+
async getMaxEmailTemplates() {
|
|
5130
|
+
const license2 = await this.getCurrentLicense();
|
|
5131
|
+
const features2 = requireFeatures();
|
|
5132
|
+
return features2.getMaxEmailTemplates(license2);
|
|
5133
|
+
},
|
|
5134
|
+
/**
|
|
5135
|
+
* Initialize license guard
|
|
5136
|
+
* Checks for existing license and starts pinging
|
|
5137
|
+
*/
|
|
5138
|
+
async initialize() {
|
|
5139
|
+
try {
|
|
5140
|
+
log.info("[INIT] Initializing License Guard...");
|
|
5141
|
+
const pluginStore = strapi2.store({
|
|
5142
|
+
type: "plugin",
|
|
5143
|
+
name: "magic-mail"
|
|
5144
|
+
});
|
|
5145
|
+
const licenseKey = await pluginStore.get({ key: "licenseKey" });
|
|
5146
|
+
const lastValidated = await pluginStore.get({ key: "lastValidated" });
|
|
5147
|
+
const now = /* @__PURE__ */ new Date();
|
|
5148
|
+
const gracePeriodHours = 24;
|
|
5149
|
+
let withinGracePeriod = false;
|
|
5083
5150
|
if (lastValidated) {
|
|
5084
5151
|
const lastValidatedDate = new Date(lastValidated);
|
|
5085
|
-
const
|
|
5086
|
-
|
|
5152
|
+
const hoursSinceValidation = (now.getTime() - lastValidatedDate.getTime()) / (1e3 * 60 * 60);
|
|
5153
|
+
withinGracePeriod = hoursSinceValidation < gracePeriodHours;
|
|
5154
|
+
}
|
|
5155
|
+
log.info("──────────────────────────────────────────────────────────");
|
|
5156
|
+
log.info(`📦 Plugin Store Check:`);
|
|
5157
|
+
if (licenseKey) {
|
|
5158
|
+
log.info(` [SUCCESS] License Key found: ${licenseKey}`);
|
|
5159
|
+
log.info(` [LICENSE] Key (short): ${licenseKey.substring(0, 10)}...`);
|
|
5160
|
+
if (lastValidated) {
|
|
5161
|
+
const lastValidatedDate = new Date(lastValidated);
|
|
5162
|
+
const hoursAgo = Math.floor((now.getTime() - lastValidatedDate.getTime()) / (1e3 * 60 * 60));
|
|
5163
|
+
log.info(` [TIME] Last validated: ${hoursAgo}h ago (Grace: ${withinGracePeriod ? "ACTIVE" : "EXPIRED"})`);
|
|
5164
|
+
} else {
|
|
5165
|
+
log.info(` [TIME] Last validated: Never (Grace: ACTIVE for first ${gracePeriodHours}h)`);
|
|
5166
|
+
}
|
|
5087
5167
|
} else {
|
|
5088
|
-
|
|
5168
|
+
log.info(` [ERROR] No license key stored`);
|
|
5089
5169
|
}
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
|
|
5117
|
-
|
|
5118
|
-
|
|
5119
|
-
|
|
5120
|
-
|
|
5121
|
-
|
|
5122
|
-
|
|
5123
|
-
|
|
5124
|
-
|
|
5125
|
-
|
|
5126
|
-
|
|
5127
|
-
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5170
|
+
log.info("──────────────────────────────────────────────────────────");
|
|
5171
|
+
if (!licenseKey) {
|
|
5172
|
+
log.info("[DEMO] No license found - Running in demo mode");
|
|
5173
|
+
log.info("[INFO] Create a license in the admin panel to activate full features");
|
|
5174
|
+
return {
|
|
5175
|
+
valid: false,
|
|
5176
|
+
demo: true,
|
|
5177
|
+
data: null
|
|
5178
|
+
};
|
|
5179
|
+
}
|
|
5180
|
+
log.info("[VERIFY] Verifying stored license key...");
|
|
5181
|
+
const verification = await this.verifyLicense(licenseKey, withinGracePeriod);
|
|
5182
|
+
if (verification.valid) {
|
|
5183
|
+
const license2 = await this.getLicenseByKey(licenseKey);
|
|
5184
|
+
log.info(`[SUCCESS] License verified online: ACTIVE (Key: ${licenseKey.substring(0, 10)}...)`);
|
|
5185
|
+
await pluginStore.set({
|
|
5186
|
+
key: "lastValidated",
|
|
5187
|
+
value: now.toISOString()
|
|
5188
|
+
});
|
|
5189
|
+
log.info("[SUCCESS] License is valid and active");
|
|
5190
|
+
const pingInterval = this.startPinging(licenseKey, 15);
|
|
5191
|
+
log.info("[PING] Started pinging license every 15 minutes");
|
|
5192
|
+
strapi2.licenseGuardMagicMail = {
|
|
5193
|
+
licenseKey,
|
|
5194
|
+
pingInterval,
|
|
5195
|
+
data: verification.data
|
|
5196
|
+
};
|
|
5197
|
+
log.info("╔════════════════════════════════════════════════════════════════╗");
|
|
5198
|
+
log.info("║ [SUCCESS] MAGIC MAIL PLUGIN LICENSE ACTIVE ║");
|
|
5199
|
+
log.info("║ ║");
|
|
5200
|
+
log.info(`║ License: ${licenseKey.padEnd(38, " ")}║`);
|
|
5201
|
+
log.info(`║ User: ${(license2?.firstName + " " + license2?.lastName).padEnd(41, " ")}║`);
|
|
5202
|
+
log.info(`║ Email: ${(license2?.email || "N/A").padEnd(40, " ")}║`);
|
|
5203
|
+
log.info("║ ║");
|
|
5204
|
+
log.info("║ [AUTO] Pinging every 15 minutes ║");
|
|
5205
|
+
log.info("╚════════════════════════════════════════════════════════════════╝");
|
|
5206
|
+
return {
|
|
5207
|
+
valid: true,
|
|
5208
|
+
demo: false,
|
|
5209
|
+
data: verification.data,
|
|
5210
|
+
gracePeriod: verification.gracePeriod || false
|
|
5211
|
+
};
|
|
5212
|
+
} else {
|
|
5213
|
+
log.error(`[ERROR] License validation failed (Key: ${licenseKey.substring(0, 10)}...)`);
|
|
5214
|
+
log.info("──────────────────────────────────────────────────────────");
|
|
5215
|
+
log.info("[WARNING] Running in demo mode with limited features");
|
|
5216
|
+
return {
|
|
5217
|
+
valid: false,
|
|
5218
|
+
demo: true,
|
|
5219
|
+
error: "Invalid or expired license",
|
|
5220
|
+
data: null
|
|
5221
|
+
};
|
|
5222
|
+
}
|
|
5223
|
+
} catch (error) {
|
|
5224
|
+
log.error("[ERROR] Error initializing License Guard:", error);
|
|
5139
5225
|
return {
|
|
5140
5226
|
valid: false,
|
|
5141
5227
|
demo: true,
|
|
5142
|
-
error:
|
|
5228
|
+
error: error.message,
|
|
5143
5229
|
data: null
|
|
5144
5230
|
};
|
|
5145
5231
|
}
|
|
5146
|
-
} catch (error) {
|
|
5147
|
-
strapi2.log.error("[ERROR] Error initializing License Guard:", error);
|
|
5148
|
-
return {
|
|
5149
|
-
valid: false,
|
|
5150
|
-
demo: true,
|
|
5151
|
-
error: error.message,
|
|
5152
|
-
data: null
|
|
5153
|
-
};
|
|
5154
5232
|
}
|
|
5155
|
-
}
|
|
5156
|
-
}
|
|
5233
|
+
};
|
|
5234
|
+
};
|
|
5157
5235
|
return licenseGuard;
|
|
5158
5236
|
}
|
|
5159
5237
|
var emailDesigner;
|