@easy-cms/core 1.17.0 → 1.18.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.
- package/dist/{chunk-LPIABPBA.js → chunk-NTAFZ4M6.js} +203 -126
- package/dist/{config-CWTw3zFm.d.ts → config-CpeC7EvC.d.ts} +33 -2
- package/dist/{handler-DzAqr9gY.d.ts → handler-BpKo6gh0.d.ts} +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +1 -1
- package/dist/internal.d.ts +3 -3
- package/dist/internal.js +3 -1
- package/dist/{plugin-BYaJUVpz.d.ts → plugin-_XG-lqA5.d.ts} +1 -1
- package/dist/plugin.d.ts +2 -2
- package/package.json +1 -1
|
@@ -45,6 +45,99 @@ var isStaff = ({ user }) => user !== null && user.member !== true;
|
|
|
45
45
|
var isSignedIn = ({ user }) => user !== null;
|
|
46
46
|
var isAdmin = ({ user }) => user?.role === "admin" && user.scoped !== true;
|
|
47
47
|
|
|
48
|
+
// src/auth/tokens.ts
|
|
49
|
+
import { createHash, createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
50
|
+
function newToken() {
|
|
51
|
+
return randomBytes(32).toString("base64url");
|
|
52
|
+
}
|
|
53
|
+
function hashToken(token) {
|
|
54
|
+
return createHash("sha256").update(token).digest("hex");
|
|
55
|
+
}
|
|
56
|
+
function hmac(secret, value) {
|
|
57
|
+
return createHmac("sha256", secret).update(value).digest("base64url");
|
|
58
|
+
}
|
|
59
|
+
function secretsOf(config) {
|
|
60
|
+
return [config.secret, ...config.previousSecrets ?? []];
|
|
61
|
+
}
|
|
62
|
+
function signedWith(secrets, value, signature) {
|
|
63
|
+
return [secrets].flat().some((secret) => safeEqual(signature, hmac(secret, value)));
|
|
64
|
+
}
|
|
65
|
+
function signToken(secret, token) {
|
|
66
|
+
return `${token}.${hmac(secret, `session:${token}`)}`;
|
|
67
|
+
}
|
|
68
|
+
function unsignToken(secrets, value) {
|
|
69
|
+
const dot = value.lastIndexOf(".");
|
|
70
|
+
if (dot <= 0) return void 0;
|
|
71
|
+
const token = value.slice(0, dot);
|
|
72
|
+
return signedWith(secrets, `session:${token}`, value.slice(dot + 1)) ? token : void 0;
|
|
73
|
+
}
|
|
74
|
+
function csrfToken(secret, token) {
|
|
75
|
+
return hmac(secret, `csrf:${token}`);
|
|
76
|
+
}
|
|
77
|
+
function csrfMatches(secrets, token, given) {
|
|
78
|
+
return signedWith(secrets, `csrf:${token}`, given);
|
|
79
|
+
}
|
|
80
|
+
function safeEqual(a, b) {
|
|
81
|
+
const left = Buffer.from(a);
|
|
82
|
+
const right = Buffer.from(b);
|
|
83
|
+
return left.length === right.length && timingSafeEqual(left, right);
|
|
84
|
+
}
|
|
85
|
+
function signPreviewToken(secret, target, expiresAt, user) {
|
|
86
|
+
const payload = Buffer.from(
|
|
87
|
+
JSON.stringify({
|
|
88
|
+
..."global" in target ? { g: target.global } : { c: target.collection, i: target.id },
|
|
89
|
+
e: expiresAt,
|
|
90
|
+
...user !== void 0 ? { u: user } : {}
|
|
91
|
+
})
|
|
92
|
+
).toString("base64url");
|
|
93
|
+
return `${payload}.${hmac(secret, `preview:${payload}`)}`;
|
|
94
|
+
}
|
|
95
|
+
function verifyPreviewToken(secrets, token, now = Date.now()) {
|
|
96
|
+
const dot = token.lastIndexOf(".");
|
|
97
|
+
if (dot <= 0) return null;
|
|
98
|
+
const payload = token.slice(0, dot);
|
|
99
|
+
if (!signedWith(secrets, `preview:${payload}`, token.slice(dot + 1))) return null;
|
|
100
|
+
try {
|
|
101
|
+
const data = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
|
|
102
|
+
if (typeof data.e !== "number" || data.e <= now) return null;
|
|
103
|
+
const user = typeof data.u === "string" ? { user: data.u } : {};
|
|
104
|
+
if (typeof data.g === "string") return { global: data.g, expiresAt: data.e, ...user };
|
|
105
|
+
if (typeof data.c === "string" && typeof data.i === "string")
|
|
106
|
+
return { collection: data.c, id: data.i, expiresAt: data.e, ...user };
|
|
107
|
+
return null;
|
|
108
|
+
} catch {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function passwordFingerprint(passwordHash) {
|
|
113
|
+
return createHash("sha256").update(typeof passwordHash === "string" ? passwordHash : "no-password").digest("base64url").slice(0, 22);
|
|
114
|
+
}
|
|
115
|
+
function signPasswordToken(secret, args) {
|
|
116
|
+
const payload = Buffer.from(
|
|
117
|
+
JSON.stringify({ u: args.userId, p: args.purpose, e: args.expiresAt })
|
|
118
|
+
).toString("base64url");
|
|
119
|
+
return `${payload}.${hmac(secret, `password:${payload}:${args.fingerprint}`)}`;
|
|
120
|
+
}
|
|
121
|
+
function readPasswordToken(token) {
|
|
122
|
+
const dot = token.lastIndexOf(".");
|
|
123
|
+
if (dot <= 0) return null;
|
|
124
|
+
const payload = token.slice(0, dot);
|
|
125
|
+
try {
|
|
126
|
+
const data = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
|
|
127
|
+
if (typeof data.u !== "string" || typeof data.e !== "number") return null;
|
|
128
|
+
if (data.p !== "reset" && data.p !== "invite" && data.p !== "verify") return null;
|
|
129
|
+
return { userId: data.u, purpose: data.p, expiresAt: data.e, payload };
|
|
130
|
+
} catch {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
function passwordTokenMatches(secrets, token, fingerprint) {
|
|
135
|
+
const dot = token.lastIndexOf(".");
|
|
136
|
+
if (dot <= 0) return false;
|
|
137
|
+
const payload = token.slice(0, dot);
|
|
138
|
+
return signedWith(secrets, `password:${payload}:${fingerprint}`, token.slice(dot + 1));
|
|
139
|
+
}
|
|
140
|
+
|
|
48
141
|
// src/builtins.ts
|
|
49
142
|
var USERS = "users";
|
|
50
143
|
var MEDIA = "media";
|
|
@@ -563,7 +656,7 @@ var emailDeliveriesCollection = {
|
|
|
563
656
|
|
|
564
657
|
// src/audit.ts
|
|
565
658
|
import { AsyncLocalStorage } from "async_hooks";
|
|
566
|
-
import { createHmac } from "crypto";
|
|
659
|
+
import { createHmac as createHmac2 } from "crypto";
|
|
567
660
|
var DEFAULT_AUDIT_KEEP = 365;
|
|
568
661
|
var DEFAULT_FAILED_LOGINS = 20;
|
|
569
662
|
var MAX_VALUE = 500;
|
|
@@ -778,7 +871,7 @@ var AuditLog = class {
|
|
|
778
871
|
});
|
|
779
872
|
for (const row of result.docs) {
|
|
780
873
|
checked++;
|
|
781
|
-
if (
|
|
874
|
+
if (!this.signer(row)) invalid.push(row.id);
|
|
782
875
|
const id = Number(row.id);
|
|
783
876
|
if (previous !== void 0 && Number.isInteger(id) && id > previous + 1)
|
|
784
877
|
gaps += id - previous - 1;
|
|
@@ -797,6 +890,49 @@ var AuditLog = class {
|
|
|
797
890
|
);
|
|
798
891
|
return verification;
|
|
799
892
|
}
|
|
893
|
+
/** The secret an entry was signed with: the current one, a previous one, or none (changed). */
|
|
894
|
+
signer(row) {
|
|
895
|
+
return secretsOf(this.cms.config).find((secret) => row.signature === this.sign(row, secret));
|
|
896
|
+
}
|
|
897
|
+
/**
|
|
898
|
+
* After `secret` changed: signs again, with the current secret, the entries signed with one of
|
|
899
|
+
* `previousSecrets`, so they still verify once it is removed. Entries no secret verifies were
|
|
900
|
+
* changed: they are left as they are, and reported. Records `audit.resign`.
|
|
901
|
+
*/
|
|
902
|
+
async resign() {
|
|
903
|
+
const invalid = [];
|
|
904
|
+
let checked = 0;
|
|
905
|
+
let resigned = 0;
|
|
906
|
+
for (let page = 1; ; page++) {
|
|
907
|
+
const result = await this.cms.db.find({
|
|
908
|
+
collection: AUDIT_LOGS,
|
|
909
|
+
sort: ["id"],
|
|
910
|
+
limit: 500,
|
|
911
|
+
page
|
|
912
|
+
});
|
|
913
|
+
for (const row of result.docs) {
|
|
914
|
+
checked++;
|
|
915
|
+
const secret = this.signer(row);
|
|
916
|
+
if (secret === void 0) invalid.push(row.id);
|
|
917
|
+
else if (secret !== this.cms.config.secret) {
|
|
918
|
+
const { id, ...data } = row;
|
|
919
|
+
await this.cms.db.update({
|
|
920
|
+
collection: AUDIT_LOGS,
|
|
921
|
+
id,
|
|
922
|
+
data: { ...data, signature: this.sign(row) }
|
|
923
|
+
});
|
|
924
|
+
resigned++;
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
if (page >= result.totalPages) break;
|
|
928
|
+
}
|
|
929
|
+
await this.record({
|
|
930
|
+
action: "audit.resign",
|
|
931
|
+
target: "audit",
|
|
932
|
+
detail: { checked, resigned, invalid: invalid.length }
|
|
933
|
+
});
|
|
934
|
+
return { checked, resigned, invalid };
|
|
935
|
+
}
|
|
800
936
|
/**
|
|
801
937
|
* Daily upkeep from `runJobs`: deletes entries older than `keep` days, then verifies the log.
|
|
802
938
|
* Runs when the last check is more than a day old.
|
|
@@ -847,11 +983,11 @@ var AuditLog = class {
|
|
|
847
983
|
const scope = this.settings.scope;
|
|
848
984
|
return (scope && context ? scope({ context, user }) : null) ?? null;
|
|
849
985
|
}
|
|
850
|
-
sign(row) {
|
|
986
|
+
sign(row, secret = this.cms.config.secret) {
|
|
851
987
|
const values = SIGNED.map((key) => row[key] ?? null);
|
|
852
988
|
if (typeof row.scope === "string" && row.scope) values.push(row.scope);
|
|
853
989
|
const payload = stable(values);
|
|
854
|
-
return
|
|
990
|
+
return createHmac2("sha256", secret).update(`audit:${payload}`).digest("base64url");
|
|
855
991
|
}
|
|
856
992
|
async lastVerification() {
|
|
857
993
|
const { docs } = await this.cms.db.find({
|
|
@@ -903,7 +1039,7 @@ function toEntry(row) {
|
|
|
903
1039
|
}
|
|
904
1040
|
|
|
905
1041
|
// src/api-keys.ts
|
|
906
|
-
import { createHash, randomBytes, timingSafeEqual } from "crypto";
|
|
1042
|
+
import { createHash as createHash2, randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
907
1043
|
var API_KEYS = "api-keys";
|
|
908
1044
|
var API_KEY_OPERATIONS = ["read", "create", "update", "delete", "publish"];
|
|
909
1045
|
var API_KEY_GLOBAL_OPERATIONS = ["read", "update", "publish"];
|
|
@@ -913,12 +1049,12 @@ function isApiKey(token) {
|
|
|
913
1049
|
return token.startsWith("ecms_");
|
|
914
1050
|
}
|
|
915
1051
|
function newApiKey() {
|
|
916
|
-
const prefix =
|
|
917
|
-
const secret =
|
|
1052
|
+
const prefix = randomBytes2(4).toString("hex");
|
|
1053
|
+
const secret = randomBytes2(32).toString("base64url");
|
|
918
1054
|
return { key: `ecms_${prefix}_${secret}`, prefix, hash: hashSecret(secret) };
|
|
919
1055
|
}
|
|
920
1056
|
function hashSecret(secret) {
|
|
921
|
-
return
|
|
1057
|
+
return createHash2("sha256").update(secret).digest("hex");
|
|
922
1058
|
}
|
|
923
1059
|
function parseApiKey(token) {
|
|
924
1060
|
const match = KEY_PATTERN.exec(token);
|
|
@@ -928,7 +1064,7 @@ function secretMatches(secret, hash) {
|
|
|
928
1064
|
if (typeof hash !== "string") return false;
|
|
929
1065
|
const a = Buffer.from(hashSecret(secret), "hex");
|
|
930
1066
|
const b = Buffer.from(hash, "hex");
|
|
931
|
-
return a.length === b.length &&
|
|
1067
|
+
return a.length === b.length && timingSafeEqual2(a, b);
|
|
932
1068
|
}
|
|
933
1069
|
function keyAllows(user, target, operation) {
|
|
934
1070
|
const key = user?.apiKey;
|
|
@@ -1035,20 +1171,23 @@ function cleanPermissions(value, known) {
|
|
|
1035
1171
|
}
|
|
1036
1172
|
|
|
1037
1173
|
// src/spam.ts
|
|
1038
|
-
import { createHmac as
|
|
1174
|
+
import { createHmac as createHmac3, timingSafeEqual as timingSafeEqual3 } from "crypto";
|
|
1039
1175
|
var MAX_AGE = 24 * 36e5;
|
|
1040
|
-
var sign = (secret, value) =>
|
|
1176
|
+
var sign = (secret, value) => createHmac3("sha256", secret).update(value).digest("base64url");
|
|
1041
1177
|
function formToken(secret, purpose, now = Date.now()) {
|
|
1042
1178
|
return `${now}.${sign(secret, `${purpose}:${now}`)}`;
|
|
1043
1179
|
}
|
|
1044
|
-
function checkFormToken(
|
|
1180
|
+
function checkFormToken(secrets, purpose, token, minTime, now = Date.now()) {
|
|
1045
1181
|
if (typeof token !== "string") return "invalid";
|
|
1046
1182
|
const [time, signature] = token.split(".");
|
|
1047
1183
|
const issued = Number(time);
|
|
1048
1184
|
if (!Number.isFinite(issued) || !signature) return "invalid";
|
|
1049
|
-
const expected = Buffer.from(sign(secret, `${purpose}:${issued}`));
|
|
1050
1185
|
const given = Buffer.from(signature);
|
|
1051
|
-
|
|
1186
|
+
const genuine = [secrets].flat().some((secret) => {
|
|
1187
|
+
const expected = Buffer.from(sign(secret, `${purpose}:${issued}`));
|
|
1188
|
+
return expected.length === given.length && timingSafeEqual3(expected, given);
|
|
1189
|
+
});
|
|
1190
|
+
if (!genuine) return "invalid";
|
|
1052
1191
|
if (now - issued < minTime) return "too-fast";
|
|
1053
1192
|
if (now - issued > MAX_AGE) return "expired";
|
|
1054
1193
|
return "ok";
|
|
@@ -1172,7 +1311,7 @@ var DEFAULT_PASSWORD_EMAILS = {
|
|
|
1172
1311
|
};
|
|
1173
1312
|
|
|
1174
1313
|
// src/auth/password.ts
|
|
1175
|
-
import { randomBytes as
|
|
1314
|
+
import { randomBytes as randomBytes3, scrypt, timingSafeEqual as timingSafeEqual4 } from "crypto";
|
|
1176
1315
|
var MIN_PASSWORD_LENGTH = 8;
|
|
1177
1316
|
var N = 2 ** 17;
|
|
1178
1317
|
var R = 8;
|
|
@@ -1191,7 +1330,7 @@ function derive(password, salt, n, r, p, length) {
|
|
|
1191
1330
|
});
|
|
1192
1331
|
}
|
|
1193
1332
|
async function hashPassword(password) {
|
|
1194
|
-
const salt =
|
|
1333
|
+
const salt = randomBytes3(16);
|
|
1195
1334
|
const key = await derive(password, salt, N, R, P, KEY_LENGTH);
|
|
1196
1335
|
return ["scrypt", N, R, P, salt.toString("base64url"), key.toString("base64url")].join("$");
|
|
1197
1336
|
}
|
|
@@ -1207,7 +1346,7 @@ async function verifyPassword(password, stored) {
|
|
|
1207
1346
|
Number(p),
|
|
1208
1347
|
expected.length
|
|
1209
1348
|
);
|
|
1210
|
-
return key.length === expected.length &&
|
|
1349
|
+
return key.length === expected.length && timingSafeEqual4(key, expected);
|
|
1211
1350
|
}
|
|
1212
1351
|
var dummyHash;
|
|
1213
1352
|
async function fakeVerify(password) {
|
|
@@ -1218,92 +1357,6 @@ async function fakeVerify(password) {
|
|
|
1218
1357
|
|
|
1219
1358
|
// src/auth/sso.ts
|
|
1220
1359
|
import { createHmac as createHmac4, randomBytes as randomBytes4 } from "crypto";
|
|
1221
|
-
|
|
1222
|
-
// src/auth/tokens.ts
|
|
1223
|
-
import { createHash as createHash2, createHmac as createHmac3, randomBytes as randomBytes3, timingSafeEqual as timingSafeEqual4 } from "crypto";
|
|
1224
|
-
function newToken() {
|
|
1225
|
-
return randomBytes3(32).toString("base64url");
|
|
1226
|
-
}
|
|
1227
|
-
function hashToken(token) {
|
|
1228
|
-
return createHash2("sha256").update(token).digest("hex");
|
|
1229
|
-
}
|
|
1230
|
-
function hmac(secret, value) {
|
|
1231
|
-
return createHmac3("sha256", secret).update(value).digest("base64url");
|
|
1232
|
-
}
|
|
1233
|
-
function signToken(secret, token) {
|
|
1234
|
-
return `${token}.${hmac(secret, `session:${token}`)}`;
|
|
1235
|
-
}
|
|
1236
|
-
function unsignToken(secret, value) {
|
|
1237
|
-
const dot = value.lastIndexOf(".");
|
|
1238
|
-
if (dot <= 0) return void 0;
|
|
1239
|
-
const token = value.slice(0, dot);
|
|
1240
|
-
return safeEqual(value.slice(dot + 1), hmac(secret, `session:${token}`)) ? token : void 0;
|
|
1241
|
-
}
|
|
1242
|
-
function csrfToken(secret, token) {
|
|
1243
|
-
return hmac(secret, `csrf:${token}`);
|
|
1244
|
-
}
|
|
1245
|
-
function safeEqual(a, b) {
|
|
1246
|
-
const left = Buffer.from(a);
|
|
1247
|
-
const right = Buffer.from(b);
|
|
1248
|
-
return left.length === right.length && timingSafeEqual4(left, right);
|
|
1249
|
-
}
|
|
1250
|
-
function signPreviewToken(secret, target, expiresAt, user) {
|
|
1251
|
-
const payload = Buffer.from(
|
|
1252
|
-
JSON.stringify({
|
|
1253
|
-
..."global" in target ? { g: target.global } : { c: target.collection, i: target.id },
|
|
1254
|
-
e: expiresAt,
|
|
1255
|
-
...user !== void 0 ? { u: user } : {}
|
|
1256
|
-
})
|
|
1257
|
-
).toString("base64url");
|
|
1258
|
-
return `${payload}.${hmac(secret, `preview:${payload}`)}`;
|
|
1259
|
-
}
|
|
1260
|
-
function verifyPreviewToken(secret, token, now = Date.now()) {
|
|
1261
|
-
const dot = token.lastIndexOf(".");
|
|
1262
|
-
if (dot <= 0) return null;
|
|
1263
|
-
const payload = token.slice(0, dot);
|
|
1264
|
-
if (!safeEqual(token.slice(dot + 1), hmac(secret, `preview:${payload}`))) return null;
|
|
1265
|
-
try {
|
|
1266
|
-
const data = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
|
|
1267
|
-
if (typeof data.e !== "number" || data.e <= now) return null;
|
|
1268
|
-
const user = typeof data.u === "string" ? { user: data.u } : {};
|
|
1269
|
-
if (typeof data.g === "string") return { global: data.g, expiresAt: data.e, ...user };
|
|
1270
|
-
if (typeof data.c === "string" && typeof data.i === "string")
|
|
1271
|
-
return { collection: data.c, id: data.i, expiresAt: data.e, ...user };
|
|
1272
|
-
return null;
|
|
1273
|
-
} catch {
|
|
1274
|
-
return null;
|
|
1275
|
-
}
|
|
1276
|
-
}
|
|
1277
|
-
function passwordFingerprint(passwordHash) {
|
|
1278
|
-
return createHash2("sha256").update(typeof passwordHash === "string" ? passwordHash : "no-password").digest("base64url").slice(0, 22);
|
|
1279
|
-
}
|
|
1280
|
-
function signPasswordToken(secret, args) {
|
|
1281
|
-
const payload = Buffer.from(
|
|
1282
|
-
JSON.stringify({ u: args.userId, p: args.purpose, e: args.expiresAt })
|
|
1283
|
-
).toString("base64url");
|
|
1284
|
-
return `${payload}.${hmac(secret, `password:${payload}:${args.fingerprint}`)}`;
|
|
1285
|
-
}
|
|
1286
|
-
function readPasswordToken(token) {
|
|
1287
|
-
const dot = token.lastIndexOf(".");
|
|
1288
|
-
if (dot <= 0) return null;
|
|
1289
|
-
const payload = token.slice(0, dot);
|
|
1290
|
-
try {
|
|
1291
|
-
const data = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
|
|
1292
|
-
if (typeof data.u !== "string" || typeof data.e !== "number") return null;
|
|
1293
|
-
if (data.p !== "reset" && data.p !== "invite" && data.p !== "verify") return null;
|
|
1294
|
-
return { userId: data.u, purpose: data.p, expiresAt: data.e, payload };
|
|
1295
|
-
} catch {
|
|
1296
|
-
return null;
|
|
1297
|
-
}
|
|
1298
|
-
}
|
|
1299
|
-
function passwordTokenMatches(secret, token, fingerprint) {
|
|
1300
|
-
const dot = token.lastIndexOf(".");
|
|
1301
|
-
if (dot <= 0) return false;
|
|
1302
|
-
const payload = token.slice(0, dot);
|
|
1303
|
-
return safeEqual(token.slice(dot + 1), hmac(secret, `password:${payload}:${fingerprint}`));
|
|
1304
|
-
}
|
|
1305
|
-
|
|
1306
|
-
// src/auth/sso.ts
|
|
1307
1360
|
var SSO_COOKIE = "ecms-sso";
|
|
1308
1361
|
var PENDING_TTL = 10 * 6e4;
|
|
1309
1362
|
var random = () => randomBytes4(32).toString("base64url");
|
|
@@ -1314,12 +1367,13 @@ function seal(secret, pending) {
|
|
|
1314
1367
|
const payload = Buffer.from(JSON.stringify(pending)).toString("base64url");
|
|
1315
1368
|
return `${payload}.${sign2(secret, payload)}`;
|
|
1316
1369
|
}
|
|
1317
|
-
function unseal(
|
|
1370
|
+
function unseal(secrets, value) {
|
|
1318
1371
|
if (!value) return null;
|
|
1319
1372
|
const dot = value.lastIndexOf(".");
|
|
1320
1373
|
if (dot <= 0) return null;
|
|
1321
1374
|
const payload = value.slice(0, dot);
|
|
1322
|
-
|
|
1375
|
+
const signature = value.slice(dot + 1);
|
|
1376
|
+
if (![secrets].flat().some((secret) => safeEqual(signature, sign2(secret, payload)))) return null;
|
|
1323
1377
|
try {
|
|
1324
1378
|
const pending = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
|
|
1325
1379
|
return typeof pending.e === "number" && pending.e > Date.now() ? pending : null;
|
|
@@ -1387,7 +1441,7 @@ var SingleSignOn = class {
|
|
|
1387
1441
|
*/
|
|
1388
1442
|
async finish(providerId, options) {
|
|
1389
1443
|
const admin = this.config.admin.path.replace(/\/+$/, "");
|
|
1390
|
-
const pending = unseal(this.config
|
|
1444
|
+
const pending = unseal(secretsOf(this.config), options.cookie);
|
|
1391
1445
|
let email2 = null;
|
|
1392
1446
|
const back = async (page2, outcome) => {
|
|
1393
1447
|
await this.cms.audit.record({
|
|
@@ -1839,7 +1893,7 @@ var Auth = class {
|
|
|
1839
1893
|
await this.recordFailure(key);
|
|
1840
1894
|
throw refuse("form", "could not be sent");
|
|
1841
1895
|
}
|
|
1842
|
-
const checked = checkFormToken(this.
|
|
1896
|
+
const checked = checkFormToken(this.secrets, SIGNUP_FORM, args.token, SIGNUP_MIN_TIME);
|
|
1843
1897
|
if (checked !== "ok")
|
|
1844
1898
|
throw refuse(
|
|
1845
1899
|
"form",
|
|
@@ -1899,7 +1953,7 @@ var Auth = class {
|
|
|
1899
1953
|
const id = claims && (/^\d+$/.test(claims.userId) ? Number(claims.userId) : claims.userId);
|
|
1900
1954
|
const user = claims && claims.purpose === "verify" && claims.expiresAt > Date.now() && id !== null ? await this.db.findById({ collection: USERS, id }) : null;
|
|
1901
1955
|
if (!user || user.active === false || // A link confirms once: it doesn't sign in again afterwards.
|
|
1902
|
-
user.emailVerified !== false || !passwordTokenMatches(this.
|
|
1956
|
+
user.emailVerified !== false || !passwordTokenMatches(this.secrets, token, passwordFingerprint(user.passwordHash))) {
|
|
1903
1957
|
await this.recordFailure(key);
|
|
1904
1958
|
throw new ValidationError(USERS, [
|
|
1905
1959
|
{ field: "token", message: "This link has expired or is not valid" }
|
|
@@ -1969,7 +2023,7 @@ var Auth = class {
|
|
|
1969
2023
|
}
|
|
1970
2024
|
/** Ends the session for a signed token. Unknown tokens are ignored. */
|
|
1971
2025
|
async logout(signedToken) {
|
|
1972
|
-
const token = unsignToken(this.
|
|
2026
|
+
const token = unsignToken(this.secrets, signedToken);
|
|
1973
2027
|
if (!token) return;
|
|
1974
2028
|
const session = await this.findSession(token);
|
|
1975
2029
|
if (!session) return;
|
|
@@ -1999,7 +2053,7 @@ var Auth = class {
|
|
|
1999
2053
|
async verify(signedToken) {
|
|
2000
2054
|
if (!signedToken) return null;
|
|
2001
2055
|
if (isApiKey(signedToken)) return this.verifyApiKey(signedToken);
|
|
2002
|
-
const token = unsignToken(this.
|
|
2056
|
+
const token = unsignToken(this.secrets, signedToken);
|
|
2003
2057
|
if (!token) return null;
|
|
2004
2058
|
const session = await this.findSession(token);
|
|
2005
2059
|
if (!session) return null;
|
|
@@ -2019,9 +2073,21 @@ var Auth = class {
|
|
|
2019
2073
|
}
|
|
2020
2074
|
/** The CSRF token clients must echo for a signed session token. @internal */
|
|
2021
2075
|
csrfFor(signedToken) {
|
|
2022
|
-
const token = unsignToken(this.
|
|
2076
|
+
const token = unsignToken(this.secrets, signedToken);
|
|
2023
2077
|
return token ? csrfToken(this.config.secret, token) : void 0;
|
|
2024
2078
|
}
|
|
2079
|
+
/**
|
|
2080
|
+
* Whether `given` is the session's CSRF token, made with the current secret or a previous one
|
|
2081
|
+
* (a client that fetched it before the secret changed). @internal
|
|
2082
|
+
*/
|
|
2083
|
+
csrfMatches(signedToken, given) {
|
|
2084
|
+
const token = unsignToken(this.secrets, signedToken);
|
|
2085
|
+
return token !== void 0 && csrfMatches(this.secrets, token, given);
|
|
2086
|
+
}
|
|
2087
|
+
/** The current secret and `previousSecrets`, which still verify. */
|
|
2088
|
+
get secrets() {
|
|
2089
|
+
return secretsOf(this.config);
|
|
2090
|
+
}
|
|
2025
2091
|
/** Starts a new session for a user, e.g. after they changed their own password. */
|
|
2026
2092
|
async createSession(userId) {
|
|
2027
2093
|
const user = await this.db.findById({ collection: USERS, id: userId });
|
|
@@ -2144,7 +2210,7 @@ var Auth = class {
|
|
|
2144
2210
|
const user = await this.db.findById({ collection: USERS, id });
|
|
2145
2211
|
if (!user || user.active === false || !this.sso.passwordAllowed(user)) return null;
|
|
2146
2212
|
const fingerprint = passwordFingerprint(user.passwordHash);
|
|
2147
|
-
if (!passwordTokenMatches(this.
|
|
2213
|
+
if (!passwordTokenMatches(this.secrets, token, fingerprint)) return null;
|
|
2148
2214
|
return { user, purpose: claims.purpose };
|
|
2149
2215
|
}
|
|
2150
2216
|
async mailPasswordLink(user, purpose, options) {
|
|
@@ -3911,7 +3977,7 @@ var VersionStore = class {
|
|
|
3911
3977
|
};
|
|
3912
3978
|
|
|
3913
3979
|
// src/local-api.ts
|
|
3914
|
-
import { createHash as createHash5, createHmac as createHmac7, randomBytes as randomBytes6, randomUUID as randomUUID3
|
|
3980
|
+
import { createHash as createHash5, createHmac as createHmac7, randomBytes as randomBytes6, randomUUID as randomUUID3 } from "crypto";
|
|
3915
3981
|
|
|
3916
3982
|
// src/auth/common-passwords.ts
|
|
3917
3983
|
var LIST = `
|
|
@@ -4647,7 +4713,7 @@ function read(response, maxBytes, deadline) {
|
|
|
4647
4713
|
|
|
4648
4714
|
// src/config-keys.ts
|
|
4649
4715
|
var keys = (list) => new Set(list.split(/\s+/).filter(Boolean));
|
|
4650
|
-
var CONFIG = keys(`secret db serverURL cors cronSecret timeZone webhooks events jobs localization routes admin
|
|
4716
|
+
var CONFIG = keys(`secret previousSecrets db serverURL cors cronSecret timeZone webhooks events jobs localization routes admin
|
|
4651
4717
|
upload auth collections globals endpoints cliCommands onRequest fieldTypes apiKeys email backups
|
|
4652
4718
|
audit logs countCacheSeconds maxPage httpCache outbox search telemetry plugins`);
|
|
4653
4719
|
var ADMIN = keys("path locale brand siteURL nav commands modules pages dashboard switcher");
|
|
@@ -5417,6 +5483,7 @@ function validateConfig(config) {
|
|
|
5417
5483
|
return issues;
|
|
5418
5484
|
}
|
|
5419
5485
|
validateSecret(config.secret, add);
|
|
5486
|
+
validatePreviousSecrets(config.previousSecrets, config.secret, add);
|
|
5420
5487
|
validateCronSecret(config.cronSecret, (issue) => issues.push(issue));
|
|
5421
5488
|
checkConfigKeys(config, (issue) => issues.push(issue));
|
|
5422
5489
|
validateAdapterVersions(config, add);
|
|
@@ -5502,6 +5569,22 @@ function validateSecret(secret, add) {
|
|
|
5502
5569
|
add("secret", "looks like an example or a repeated pattern, not a random string", hint);
|
|
5503
5570
|
}
|
|
5504
5571
|
}
|
|
5572
|
+
function validatePreviousSecrets(value, secret, add) {
|
|
5573
|
+
if (value === void 0) return;
|
|
5574
|
+
if (!Array.isArray(value)) {
|
|
5575
|
+
add("previousSecrets", "must be an array of strings", "e.g. previousSecrets: [oldSecret]");
|
|
5576
|
+
return;
|
|
5577
|
+
}
|
|
5578
|
+
for (const [i, previous] of value.entries()) {
|
|
5579
|
+
if (typeof previous !== "string" || previous.length < MIN_SECRET_LENGTH)
|
|
5580
|
+
add(
|
|
5581
|
+
`previousSecrets[${i}]`,
|
|
5582
|
+
`must be a string of at least ${MIN_SECRET_LENGTH} characters, like secret`
|
|
5583
|
+
);
|
|
5584
|
+
else if (previous === secret)
|
|
5585
|
+
add(`previousSecrets[${i}]`, "is the same as secret", "list only secrets used before it");
|
|
5586
|
+
}
|
|
5587
|
+
}
|
|
5505
5588
|
function validateCronSecret(value, push) {
|
|
5506
5589
|
const hint = `use a random string of at least ${MIN_SECRET_LENGTH} characters, e.g. \`openssl rand -hex 32\``;
|
|
5507
5590
|
if (value !== void 0) {
|
|
@@ -7083,7 +7166,7 @@ function cacheableResponse(request, body, status, headers, times, tags) {
|
|
|
7083
7166
|
}
|
|
7084
7167
|
|
|
7085
7168
|
// src/version.ts
|
|
7086
|
-
var VERSION = true ? "1.
|
|
7169
|
+
var VERSION = true ? "1.18.0" : "0.0.0-dev";
|
|
7087
7170
|
|
|
7088
7171
|
// src/telemetry.ts
|
|
7089
7172
|
var DB_CALLS = /* @__PURE__ */ new Set([
|
|
@@ -7754,11 +7837,7 @@ var EasyCMS = class {
|
|
|
7754
7837
|
verify(purpose, token) {
|
|
7755
7838
|
const [payload, signature] = String(token).split(".");
|
|
7756
7839
|
if (!payload || !signature) return void 0;
|
|
7757
|
-
|
|
7758
|
-
createHmac7("sha256", this.config.secret).update(`${purpose}:${payload}`).digest("base64url")
|
|
7759
|
-
);
|
|
7760
|
-
const given = Buffer.from(signature);
|
|
7761
|
-
if (expected.length !== given.length || !timingSafeEqual6(expected, given)) return void 0;
|
|
7840
|
+
if (!signedWith(secretsOf(this.config), `${purpose}:${payload}`, signature)) return void 0;
|
|
7762
7841
|
try {
|
|
7763
7842
|
return JSON.parse(Buffer.from(payload, "base64url").toString());
|
|
7764
7843
|
} catch {
|
|
@@ -7875,9 +7954,7 @@ var EasyCMS = class {
|
|
|
7875
7954
|
verifyMediaSignature(key, expires, signature) {
|
|
7876
7955
|
const at = Number(expires);
|
|
7877
7956
|
if (!signature || !Number.isInteger(at) || at < Date.now() / 1e3) return false;
|
|
7878
|
-
|
|
7879
|
-
const given = Buffer.from(signature);
|
|
7880
|
-
return expected.length === given.length && timingSafeEqual6(expected, given);
|
|
7957
|
+
return signedWith(secretsOf(this.config), `media:${key}:${at}`, signature);
|
|
7881
7958
|
}
|
|
7882
7959
|
mediaSignature(key, expires) {
|
|
7883
7960
|
return createHmac7("sha256", this.config.secret).update(`media:${key}:${expires}`).digest("base64url");
|
|
@@ -8170,7 +8247,7 @@ var EasyCMS = class {
|
|
|
8170
8247
|
}
|
|
8171
8248
|
/** What a preview token opens, or `null` when it is invalid or expired. */
|
|
8172
8249
|
verifyPreviewToken(token) {
|
|
8173
|
-
return token ? verifyPreviewToken(this.config
|
|
8250
|
+
return token ? verifyPreviewToken(secretsOf(this.config), token) : null;
|
|
8174
8251
|
}
|
|
8175
8252
|
/** Live preview of a global. See `preview`. */
|
|
8176
8253
|
async previewGlobal(slug2, data, options = {}) {
|
|
@@ -13136,9 +13213,8 @@ function checkCsrf(cms, ctx) {
|
|
|
13136
13213
|
if (origin === null && fetchSite === "cross-site")
|
|
13137
13214
|
throw new ForbiddenError("CSRF check failed: cross-site request");
|
|
13138
13215
|
if (ctx.via === "cookie" && ctx.token) {
|
|
13139
|
-
const expected = cms.auth.csrfFor(ctx.token);
|
|
13140
13216
|
const given = ctx.request.headers.get(CSRF_HEADER);
|
|
13141
|
-
if (!
|
|
13217
|
+
if (!given || !cms.auth.csrfMatches(ctx.token, given)) {
|
|
13142
13218
|
throw new ForbiddenError(
|
|
13143
13219
|
`CSRF check failed: send the ${CSRF_HEADER} header from GET /auth/me`
|
|
13144
13220
|
);
|
|
@@ -13538,6 +13614,7 @@ export {
|
|
|
13538
13614
|
isStaff,
|
|
13539
13615
|
isSignedIn,
|
|
13540
13616
|
isAdmin,
|
|
13617
|
+
secretsOf,
|
|
13541
13618
|
MEDIA,
|
|
13542
13619
|
MEDIA_FOLDERS,
|
|
13543
13620
|
INTERNAL_COLLECTIONS,
|
|
@@ -356,6 +356,16 @@ interface BundleHints {
|
|
|
356
356
|
readonly traceInclude: readonly string[];
|
|
357
357
|
}
|
|
358
358
|
|
|
359
|
+
/**
|
|
360
|
+
* Secrets that verify: the current one first, then `previousSecrets` while one is replaced. New
|
|
361
|
+
* values are always signed with the current one.
|
|
362
|
+
*/
|
|
363
|
+
type Secrets = string | readonly string[];
|
|
364
|
+
/** The secrets of a config, the current one first. */
|
|
365
|
+
declare function secretsOf(config: {
|
|
366
|
+
readonly secret: string;
|
|
367
|
+
readonly previousSecrets?: readonly string[] | undefined;
|
|
368
|
+
}): readonly string[];
|
|
359
369
|
/** What a preview token opens: one document of a collection, or one global. */
|
|
360
370
|
type PreviewTarget = {
|
|
361
371
|
readonly collection: string;
|
|
@@ -613,6 +623,8 @@ declare class Auth {
|
|
|
613
623
|
* on the user), or `null` if it is invalid or expired.
|
|
614
624
|
*/
|
|
615
625
|
verify(signedToken: string | undefined | null): Promise<AuthUser | null>;
|
|
626
|
+
/** The current secret and `previousSecrets`, which still verify. */
|
|
627
|
+
private get secrets();
|
|
616
628
|
/** Starts a new session for a user, e.g. after they changed their own password. */
|
|
617
629
|
createSession(userId: ID): Promise<Session>;
|
|
618
630
|
/** Signs a user out everywhere. */
|
|
@@ -2460,6 +2472,18 @@ declare class AuditLog {
|
|
|
2460
2472
|
csv(filter: AuditFilter): Promise<string>;
|
|
2461
2473
|
/** Checks every entry's signature, and that no ids are missing. */
|
|
2462
2474
|
verify(): Promise<AuditVerification>;
|
|
2475
|
+
/** The secret an entry was signed with: the current one, a previous one, or none (changed). */
|
|
2476
|
+
private signer;
|
|
2477
|
+
/**
|
|
2478
|
+
* After `secret` changed: signs again, with the current secret, the entries signed with one of
|
|
2479
|
+
* `previousSecrets`, so they still verify once it is removed. Entries no secret verifies were
|
|
2480
|
+
* changed: they are left as they are, and reported. Records `audit.resign`.
|
|
2481
|
+
*/
|
|
2482
|
+
resign(): Promise<{
|
|
2483
|
+
checked: number;
|
|
2484
|
+
resigned: number;
|
|
2485
|
+
invalid: ID[];
|
|
2486
|
+
}>;
|
|
2463
2487
|
/** What the dashboard warns about: many failed logins, entries not written, a failed check. */
|
|
2464
2488
|
attention(now?: Date): Promise<({
|
|
2465
2489
|
id: 'failed-logins';
|
|
@@ -3531,6 +3555,13 @@ interface BackupsConfig {
|
|
|
3531
3555
|
interface Config {
|
|
3532
3556
|
/** Signs sessions. At least 32 characters; read it from `process.env.EASY_CMS_SECRET`. */
|
|
3533
3557
|
readonly secret: string;
|
|
3558
|
+
/**
|
|
3559
|
+
* Secrets used before `secret`, while it is replaced: what they signed (sessions, links,
|
|
3560
|
+
* tokens, the audit log) still verifies; new values are signed with `secret` only. Keep one
|
|
3561
|
+
* until sessions and links made with it have expired (7 days by default), and run
|
|
3562
|
+
* `easy-cms audit:resign` before removing it. At least 32 characters each, like `secret`.
|
|
3563
|
+
*/
|
|
3564
|
+
readonly previousSecrets?: readonly string[];
|
|
3534
3565
|
readonly db: DatabaseAdapter;
|
|
3535
3566
|
/**
|
|
3536
3567
|
* Public origin of the app, e.g. `https://example.com`. When set, media URLs are absolute
|
|
@@ -3687,5 +3718,5 @@ interface ResolvedConfig extends Omit<Config, 'cors' | 'localization' | 'routes'
|
|
|
3687
3718
|
*/
|
|
3688
3719
|
declare function defineConfig<const TConfig extends Config>(config: TConfig): TConfig;
|
|
3689
3720
|
|
|
3690
|
-
export { ADAPTER_API_VERSION as A, EasyCMS as E, AuditLog as S, Auth as V, EasyCMSError as aD, FIELD_TYPES as aK, ConfigError as al, ForbiddenError as b2, PLUGIN_API_VERSION as bB, PayloadTooLargeError as bG, QueryError as bM, ROLE_OPERATIONS as bN, Roles as bX, SchemaError as b_, NotFoundError as bv, API_KEYS as c$, WEBHOOK_EVENTS as cC, anyone as cH, consoleEmail as cI, consoleLogger as cJ, createEasyCMS as cK, defineConfig as cL, defineFieldType as cM, definePlugin as cN, diskStorage as cO, hasRows as cP, isAdmin as cQ, isHasMany as cR, isSignedIn as cS, isStaff as cT, isSystemAdmin as cU, jsonLogger as cV, memorySearch as cW, mimeAllowedBy as cX, rowFields as cY, silentLogger as cZ, uniqueWithinOf as c_, SingleSignOn as cd, TRIGRAM_LIKE_MIN as ck, TooManyRequestsError as co, UnauthorizedError as cq, ValidationError as cy, API_KEY_GLOBAL_OPERATIONS as d0, API_KEY_OPERATIONS as d1, DEFAULT_MAX_VERSIONS as d2, DEFAULT_PASSWORD_EMAILS as d3, FIELD_TYPE_BASES as d4, FOLDER_LEVELS as d5, MediaFolders as d6, SSO_COOKIE as d7, codeOfStatus as
|
|
3691
|
-
export type { AuthUser as $, AfterDeleteHook as B, Config as C, AfterReadHook as D, Field as F, ApiKeyContext as G, ApiKeyGlobalOperation as H, ID as I, ApiKeyOperation as J, ApiKeyPermissions as K, LocalizationConfig as L, ArrayField as M, AuditChange as N, AuditConfig as O, PaginatedDocs as P, AuditEntry as Q, ResolvedConfig as R, AuditPage as T, AuditVerification as U, WebhookPayload as W, AuthConfig as X, AuthProvider as Y, AuthProviderProfile as Z, AuthProviderRequest as _, FieldError as a, FindOptions as a$, BackupsConfig as a0, BeforeChangeHook as a1, BeforeDeleteHook as a2, BeforeValidateHook as a3, Block as a4, BlocksField as a5, BooleanField as a6, BuiltinApiKeysCollection as a7, BuiltinMediaCollection as a8, BuiltinMediaFoldersCollection as a9, DirectUpload as aA, DiskStorageOptions as aB, DocumentOf as aC, EmailAdapter as aE, EmailField as aF, EmailMessage as aG, Endpoint as aH, EndpointRequest as aI, ErrorCode as aJ, FieldAccess as aL, FieldAccessFn as aM, FieldAdmin as aN, FieldRule as aO, FieldType as aP, FieldTypeBase as aQ, FieldTypeDefinition as aR, FieldTypeValidateContext as aS, FieldValidate as aT, FieldValidateContext as aU, FieldValue as aV, FieldsInput as aW, FieldsValue as aX, FilterOptionsArgs as aY, FindAfterArgs as aZ, FindArgs as a_, BuiltinUsersCollection as aa, BundleHints as ab, CliCommand as ac, CollectionAccess as ad, CollectionAdmin as ae, CollectionConfig as af, CollectionDocument as ag, CollectionHooks as ah, CollectionListAdmin as ai, CollectionSearch as aj, CollectionSlug as ak, ConfigIssue as am, ContainerAdmin as an, CreateInput as ao, CreateMigrationResult as ap, CursorDocs as aq, CustomField as ar, CustomFieldTypes as as, DashboardWidget as at, Database as au, DatabaseAdapter as av, DatabaseInitArgs as aw, DatabaseTransfer as ax, DateField as ay, DepthOptions as az, FilterOptions as b, SchemaMode as b$, FolderLevel as b0, FolderPermissions as b1, GlobalAccess as b3, GlobalConfig as b4, GlobalDocument as b5, GlobalHooks as b6, GlobalInput as b7, GlobalSlug as b8, GroupField as b9, OutboxRow as bA, PasswordEmail as bC, PasswordEmailArgs as bD, PasswordEmailFn as bE, PasswordLinkOptions as bF, Plugin as bH, PluginInfo as bI, PluginTypes as bJ, PreviewTarget as bK, PreviewURL as bL, RawDocument as bO, ReadOptions as bP, RelationshipField as bQ, RequestContext as bR, RichTextDocument as bS, RichTextField as bT, Role as bU, RoleOperation as bV, RolePermissions as bW, RoutesConfig as bY, ScheduledPublish as bZ, ImageSize as ba, IncrementOptions as bb, InferCollection as bc, InferGlobal as bd, JobConfig as be, JsonField as bf, KeysetPage as bg, Label as bh, LayoutNode as bi, LivePreview as bj, LocaleOf as bk, LogDetails as bl, Logger as bm, LoginArgs as bn, LogsConfig as bo, MediaDocument as bp, MediaSize as bq, MembersConfig as br, MembersSignup as bs, MigrationInfo as bt, NavGroup as bu, NumberField as bw, OnRequest as bx, OnRequestArgs as by, Operation as bz, CreateEasyCMSOptions as c, SearchAdapter as c0, SearchEntry as c1, SearchHits as c2, SearchOptions as c3, SearchQuery as c4, SearchResults as c5, SearchSetting as c6, SelectField as c7, SelectOption as c8, Session as c9, VersionSummary as cA, VersionsConfig as cB, WebhookConfig as cD, WebhookEvent as cE, Where as cF, WhereOperators as cG, SidebarPanel as ca, SignupArgs as cb, SignupResult as cc, SlugField as ce, SlugOf as cf, SsoOutcome as cg, SsoProviderRef as ch, StorageAdapter as ci, StoredFile as cj, TelemetryConfig as cl, TextField as cm, TextareaField as cn, TypedPlugin as cp, UncountedDocs as cr, UpdateInput as cs, UpdateOptions as ct, UploadConfig as cu, UploadField as cv, UploadFromURLConfig as cw, UserIdentity as cx, Version as cz, EmailSetting as d, Access as f, AccessArgs as g, AccessOptions as h, AdminBrand as i, AdminCommand as j, AdminComponent as k, AdminConfig as l, AdminFieldArgs as m, AdminIcon as n, AdminLocale as o, AdminPage as p, AdminRole as q, AdminRoleChange as r, AdminRoleField as s, AdminRoleTarget as t, AdminRoleView as u, AdminRoles as v, AdminSso as w, AdminSwitcher as x, AdminViewAccess as y, AfterChangeHook as z };
|
|
3721
|
+
export { ADAPTER_API_VERSION as A, EasyCMS as E, AuditLog as S, Auth as V, EasyCMSError as aD, FIELD_TYPES as aK, ConfigError as al, ForbiddenError as b2, PLUGIN_API_VERSION as bB, PayloadTooLargeError as bG, QueryError as bM, ROLE_OPERATIONS as bN, Roles as bX, SchemaError as b_, NotFoundError as bv, API_KEYS as c$, WEBHOOK_EVENTS as cC, anyone as cH, consoleEmail as cI, consoleLogger as cJ, createEasyCMS as cK, defineConfig as cL, defineFieldType as cM, definePlugin as cN, diskStorage as cO, hasRows as cP, isAdmin as cQ, isHasMany as cR, isSignedIn as cS, isStaff as cT, isSystemAdmin as cU, jsonLogger as cV, memorySearch as cW, mimeAllowedBy as cX, rowFields as cY, silentLogger as cZ, uniqueWithinOf as c_, SingleSignOn as cd, TRIGRAM_LIKE_MIN as ck, TooManyRequestsError as co, UnauthorizedError as cq, ValidationError as cy, API_KEY_GLOBAL_OPERATIONS as d0, API_KEY_OPERATIONS as d1, DEFAULT_MAX_VERSIONS as d2, DEFAULT_PASSWORD_EMAILS as d3, FIELD_TYPE_BASES as d4, FOLDER_LEVELS as d5, MediaFolders as d6, SSO_COOKIE as d7, codeOfStatus as d9, isJsonLogger as da, keyAllows as db, logFormat as dc, secretsOf as dd, ADMIN_ICONS as e };
|
|
3722
|
+
export type { AuthUser as $, AfterDeleteHook as B, Config as C, AfterReadHook as D, Field as F, ApiKeyContext as G, ApiKeyGlobalOperation as H, ID as I, ApiKeyOperation as J, ApiKeyPermissions as K, LocalizationConfig as L, ArrayField as M, AuditChange as N, AuditConfig as O, PaginatedDocs as P, AuditEntry as Q, ResolvedConfig as R, AuditPage as T, AuditVerification as U, WebhookPayload as W, AuthConfig as X, AuthProvider as Y, AuthProviderProfile as Z, AuthProviderRequest as _, FieldError as a, FindOptions as a$, BackupsConfig as a0, BeforeChangeHook as a1, BeforeDeleteHook as a2, BeforeValidateHook as a3, Block as a4, BlocksField as a5, BooleanField as a6, BuiltinApiKeysCollection as a7, BuiltinMediaCollection as a8, BuiltinMediaFoldersCollection as a9, DirectUpload as aA, DiskStorageOptions as aB, DocumentOf as aC, EmailAdapter as aE, EmailField as aF, EmailMessage as aG, Endpoint as aH, EndpointRequest as aI, ErrorCode as aJ, FieldAccess as aL, FieldAccessFn as aM, FieldAdmin as aN, FieldRule as aO, FieldType as aP, FieldTypeBase as aQ, FieldTypeDefinition as aR, FieldTypeValidateContext as aS, FieldValidate as aT, FieldValidateContext as aU, FieldValue as aV, FieldsInput as aW, FieldsValue as aX, FilterOptionsArgs as aY, FindAfterArgs as aZ, FindArgs as a_, BuiltinUsersCollection as aa, BundleHints as ab, CliCommand as ac, CollectionAccess as ad, CollectionAdmin as ae, CollectionConfig as af, CollectionDocument as ag, CollectionHooks as ah, CollectionListAdmin as ai, CollectionSearch as aj, CollectionSlug as ak, ConfigIssue as am, ContainerAdmin as an, CreateInput as ao, CreateMigrationResult as ap, CursorDocs as aq, CustomField as ar, CustomFieldTypes as as, DashboardWidget as at, Database as au, DatabaseAdapter as av, DatabaseInitArgs as aw, DatabaseTransfer as ax, DateField as ay, DepthOptions as az, FilterOptions as b, SchemaMode as b$, FolderLevel as b0, FolderPermissions as b1, GlobalAccess as b3, GlobalConfig as b4, GlobalDocument as b5, GlobalHooks as b6, GlobalInput as b7, GlobalSlug as b8, GroupField as b9, OutboxRow as bA, PasswordEmail as bC, PasswordEmailArgs as bD, PasswordEmailFn as bE, PasswordLinkOptions as bF, Plugin as bH, PluginInfo as bI, PluginTypes as bJ, PreviewTarget as bK, PreviewURL as bL, RawDocument as bO, ReadOptions as bP, RelationshipField as bQ, RequestContext as bR, RichTextDocument as bS, RichTextField as bT, Role as bU, RoleOperation as bV, RolePermissions as bW, RoutesConfig as bY, ScheduledPublish as bZ, ImageSize as ba, IncrementOptions as bb, InferCollection as bc, InferGlobal as bd, JobConfig as be, JsonField as bf, KeysetPage as bg, Label as bh, LayoutNode as bi, LivePreview as bj, LocaleOf as bk, LogDetails as bl, Logger as bm, LoginArgs as bn, LogsConfig as bo, MediaDocument as bp, MediaSize as bq, MembersConfig as br, MembersSignup as bs, MigrationInfo as bt, NavGroup as bu, NumberField as bw, OnRequest as bx, OnRequestArgs as by, Operation as bz, CreateEasyCMSOptions as c, SearchAdapter as c0, SearchEntry as c1, SearchHits as c2, SearchOptions as c3, SearchQuery as c4, SearchResults as c5, SearchSetting as c6, SelectField as c7, SelectOption as c8, Session as c9, VersionSummary as cA, VersionsConfig as cB, WebhookConfig as cD, WebhookEvent as cE, Where as cF, WhereOperators as cG, SidebarPanel as ca, SignupArgs as cb, SignupResult as cc, SlugField as ce, SlugOf as cf, SsoOutcome as cg, SsoProviderRef as ch, StorageAdapter as ci, StoredFile as cj, TelemetryConfig as cl, TextField as cm, TextareaField as cn, TypedPlugin as cp, UncountedDocs as cr, UpdateInput as cs, UpdateOptions as ct, UploadConfig as cu, UploadField as cv, UploadFromURLConfig as cw, UserIdentity as cx, Version as cz, EmailSetting as d, Secrets as d8, Access as f, AccessArgs as g, AccessOptions as h, AdminBrand as i, AdminCommand as j, AdminComponent as k, AdminConfig as l, AdminFieldArgs as m, AdminIcon as n, AdminLocale as o, AdminPage as p, AdminRole as q, AdminRoleChange as r, AdminRoleField as s, AdminRoleTarget as t, AdminRoleView as u, AdminRoles as v, AdminSso as w, AdminSwitcher as x, AdminViewAccess as y, AfterChangeHook as z };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { I as ID, C as Config, E as EasyCMS, L as LocalizationConfig, F as Field, a as FieldError, b as FilterOptions, c as CreateEasyCMSOptions, R as ResolvedConfig } from './config-
|
|
1
|
+
import { I as ID, C as Config, E as EasyCMS, L as LocalizationConfig, F as Field, a as FieldError, b as FilterOptions, c as CreateEasyCMSOptions, R as ResolvedConfig } from './config-CpeC7EvC.js';
|
|
2
2
|
|
|
3
3
|
/** Decrypts a file from `encryptBackup`; throws for another key or a changed file. */
|
|
4
4
|
declare function decryptBackup(data: Uint8Array, encryptionKey: string): Uint8Array;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { P as PaginatedDocs, I as ID, d as EmailSetting, W as WebhookPayload } from './config-
|
|
2
|
-
export { A as ADAPTER_API_VERSION, e as ADMIN_ICONS, f as Access, g as AccessArgs, h as AccessOptions, i as AdminBrand, j as AdminCommand, k as AdminComponent, l as AdminConfig, m as AdminFieldArgs, n as AdminIcon, o as AdminLocale, p as AdminPage, q as AdminRole, r as AdminRoleChange, s as AdminRoleField, t as AdminRoleTarget, u as AdminRoleView, v as AdminRoles, w as AdminSso, x as AdminSwitcher, y as AdminViewAccess, z as AfterChangeHook, B as AfterDeleteHook, D as AfterReadHook, G as ApiKeyContext, H as ApiKeyGlobalOperation, J as ApiKeyOperation, K as ApiKeyPermissions, M as ArrayField, N as AuditChange, O as AuditConfig, Q as AuditEntry, S as AuditLog, T as AuditPage, U as AuditVerification, V as Auth, X as AuthConfig, Y as AuthProvider, Z as AuthProviderProfile, _ as AuthProviderRequest, $ as AuthUser, a0 as BackupsConfig, a1 as BeforeChangeHook, a2 as BeforeDeleteHook, a3 as BeforeValidateHook, a4 as Block, a5 as BlocksField, a6 as BooleanField, a7 as BuiltinApiKeysCollection, a8 as BuiltinMediaCollection, a9 as BuiltinMediaFoldersCollection, aa as BuiltinUsersCollection, ab as BundleHints, ac as CliCommand, ad as CollectionAccess, ae as CollectionAdmin, af as CollectionConfig, ag as CollectionDocument, ah as CollectionHooks, ai as CollectionListAdmin, aj as CollectionSearch, ak as CollectionSlug, C as Config, al as ConfigError, am as ConfigIssue, an as ContainerAdmin, c as CreateEasyCMSOptions, ao as CreateInput, ap as CreateMigrationResult, aq as CursorDocs, ar as CustomField, as as CustomFieldTypes, at as DashboardWidget, au as Database, av as DatabaseAdapter, aw as DatabaseInitArgs, ax as DatabaseTransfer, ay as DateField, az as DepthOptions, aA as DirectUpload, aB as DiskStorageOptions, aC as DocumentOf, E as EasyCMS, aD as EasyCMSError, aE as EmailAdapter, aF as EmailField, aG as EmailMessage, aH as Endpoint, aI as EndpointRequest, aJ as ErrorCode, aK as FIELD_TYPES, F as Field, aL as FieldAccess, aM as FieldAccessFn, aN as FieldAdmin, a as FieldError, aO as FieldRule, aP as FieldType, aQ as FieldTypeBase, aR as FieldTypeDefinition, aS as FieldTypeValidateContext, aT as FieldValidate, aU as FieldValidateContext, aV as FieldValue, aW as FieldsInput, aX as FieldsValue, b as FilterOptions, aY as FilterOptionsArgs, aZ as FindAfterArgs, a_ as FindArgs, a$ as FindOptions, b0 as FolderLevel, b1 as FolderPermissions, b2 as ForbiddenError, b3 as GlobalAccess, b4 as GlobalConfig, b5 as GlobalDocument, b6 as GlobalHooks, b7 as GlobalInput, b8 as GlobalSlug, b9 as GroupField, ba as ImageSize, bb as IncrementOptions, bc as InferCollection, bd as InferGlobal, be as JobConfig, bf as JsonField, bg as KeysetPage, bh as Label, bi as LayoutNode, bj as LivePreview, bk as LocaleOf, L as LocalizationConfig, bl as LogDetails, bm as Logger, bn as LoginArgs, bo as LogsConfig, bp as MediaDocument, bq as MediaSize, br as MembersConfig, bs as MembersSignup, bt as MigrationInfo, bu as NavGroup, bv as NotFoundError, bw as NumberField, bx as OnRequest, by as OnRequestArgs, bz as Operation, bA as OutboxRow, bB as PLUGIN_API_VERSION, bC as PasswordEmail, bD as PasswordEmailArgs, bE as PasswordEmailFn, bF as PasswordLinkOptions, bG as PayloadTooLargeError, bH as Plugin, bI as PluginInfo, bJ as PluginTypes, bK as PreviewTarget, bL as PreviewURL, bM as QueryError, bN as ROLE_OPERATIONS, bO as RawDocument, bP as ReadOptions, bQ as RelationshipField, bR as RequestContext, R as ResolvedConfig, bS as RichTextDocument, bT as RichTextField, bU as Role, bV as RoleOperation, bW as RolePermissions, bX as Roles, bY as RoutesConfig, bZ as ScheduledPublish, b_ as SchemaError, b$ as SchemaMode, c0 as SearchAdapter, c1 as SearchEntry, c2 as SearchHits, c3 as SearchOptions, c4 as SearchQuery, c5 as SearchResults, c6 as SearchSetting, c7 as SelectField, c8 as SelectOption, c9 as Session, ca as SidebarPanel, cb as SignupArgs, cc as SignupResult, cd as SingleSignOn, ce as SlugField, cf as SlugOf, cg as SsoOutcome, ch as SsoProviderRef, ci as StorageAdapter, cj as StoredFile, ck as TRIGRAM_LIKE_MIN, cl as TelemetryConfig, cm as TextField, cn as TextareaField, co as TooManyRequestsError, cp as TypedPlugin, cq as UnauthorizedError, cr as UncountedDocs, cs as UpdateInput, ct as UpdateOptions, cu as UploadConfig, cv as UploadField, cw as UploadFromURLConfig, cx as UserIdentity, cy as ValidationError, cz as Version, cA as VersionSummary, cB as VersionsConfig, cC as WEBHOOK_EVENTS, cD as WebhookConfig, cE as WebhookEvent, cF as Where, cG as WhereOperators, cH as anyone, cI as consoleEmail, cJ as consoleLogger, cK as createEasyCMS, cL as defineConfig, cM as defineFieldType, cN as definePlugin, cO as diskStorage, cP as hasRows, cQ as isAdmin, cR as isHasMany, cS as isSignedIn, cT as isStaff, cU as isSystemAdmin, cV as jsonLogger, cW as memorySearch, cX as mimeAllowedBy, cY as rowFields, cZ as silentLogger, c_ as uniqueWithinOf } from './config-
|
|
3
|
-
export { A as ADMIN_API_VERSION, a as AdminCollection, b as AdminComponentRef, c as AdminElementProps, d as AdminField, e as AdminGlobal, f as AdminLayoutNode, g as AdminNavGroup, h as AdminNavItem, i as AdminNavNode, j as AdminPageRef, k as AdminPageRoute, l as AdminSchema, m as AdminWidgetRef, S as SetFieldDetail, w as warnDeprecated } from './plugin-
|
|
4
|
-
export { A as AdminBackup, a as AdminBackups, b as ApiHandlerOptions, B as BackupState, L as LoadConfigOptions, R as RestHandler, c as RestHandlerOptions, d as createApiHandler, e as createRestHandler, l as loadConfig, r as resolveConfig, s as sharedEasyCMS, f as slugify } from './handler-
|
|
1
|
+
import { P as PaginatedDocs, I as ID, d as EmailSetting, W as WebhookPayload } from './config-CpeC7EvC.js';
|
|
2
|
+
export { A as ADAPTER_API_VERSION, e as ADMIN_ICONS, f as Access, g as AccessArgs, h as AccessOptions, i as AdminBrand, j as AdminCommand, k as AdminComponent, l as AdminConfig, m as AdminFieldArgs, n as AdminIcon, o as AdminLocale, p as AdminPage, q as AdminRole, r as AdminRoleChange, s as AdminRoleField, t as AdminRoleTarget, u as AdminRoleView, v as AdminRoles, w as AdminSso, x as AdminSwitcher, y as AdminViewAccess, z as AfterChangeHook, B as AfterDeleteHook, D as AfterReadHook, G as ApiKeyContext, H as ApiKeyGlobalOperation, J as ApiKeyOperation, K as ApiKeyPermissions, M as ArrayField, N as AuditChange, O as AuditConfig, Q as AuditEntry, S as AuditLog, T as AuditPage, U as AuditVerification, V as Auth, X as AuthConfig, Y as AuthProvider, Z as AuthProviderProfile, _ as AuthProviderRequest, $ as AuthUser, a0 as BackupsConfig, a1 as BeforeChangeHook, a2 as BeforeDeleteHook, a3 as BeforeValidateHook, a4 as Block, a5 as BlocksField, a6 as BooleanField, a7 as BuiltinApiKeysCollection, a8 as BuiltinMediaCollection, a9 as BuiltinMediaFoldersCollection, aa as BuiltinUsersCollection, ab as BundleHints, ac as CliCommand, ad as CollectionAccess, ae as CollectionAdmin, af as CollectionConfig, ag as CollectionDocument, ah as CollectionHooks, ai as CollectionListAdmin, aj as CollectionSearch, ak as CollectionSlug, C as Config, al as ConfigError, am as ConfigIssue, an as ContainerAdmin, c as CreateEasyCMSOptions, ao as CreateInput, ap as CreateMigrationResult, aq as CursorDocs, ar as CustomField, as as CustomFieldTypes, at as DashboardWidget, au as Database, av as DatabaseAdapter, aw as DatabaseInitArgs, ax as DatabaseTransfer, ay as DateField, az as DepthOptions, aA as DirectUpload, aB as DiskStorageOptions, aC as DocumentOf, E as EasyCMS, aD as EasyCMSError, aE as EmailAdapter, aF as EmailField, aG as EmailMessage, aH as Endpoint, aI as EndpointRequest, aJ as ErrorCode, aK as FIELD_TYPES, F as Field, aL as FieldAccess, aM as FieldAccessFn, aN as FieldAdmin, a as FieldError, aO as FieldRule, aP as FieldType, aQ as FieldTypeBase, aR as FieldTypeDefinition, aS as FieldTypeValidateContext, aT as FieldValidate, aU as FieldValidateContext, aV as FieldValue, aW as FieldsInput, aX as FieldsValue, b as FilterOptions, aY as FilterOptionsArgs, aZ as FindAfterArgs, a_ as FindArgs, a$ as FindOptions, b0 as FolderLevel, b1 as FolderPermissions, b2 as ForbiddenError, b3 as GlobalAccess, b4 as GlobalConfig, b5 as GlobalDocument, b6 as GlobalHooks, b7 as GlobalInput, b8 as GlobalSlug, b9 as GroupField, ba as ImageSize, bb as IncrementOptions, bc as InferCollection, bd as InferGlobal, be as JobConfig, bf as JsonField, bg as KeysetPage, bh as Label, bi as LayoutNode, bj as LivePreview, bk as LocaleOf, L as LocalizationConfig, bl as LogDetails, bm as Logger, bn as LoginArgs, bo as LogsConfig, bp as MediaDocument, bq as MediaSize, br as MembersConfig, bs as MembersSignup, bt as MigrationInfo, bu as NavGroup, bv as NotFoundError, bw as NumberField, bx as OnRequest, by as OnRequestArgs, bz as Operation, bA as OutboxRow, bB as PLUGIN_API_VERSION, bC as PasswordEmail, bD as PasswordEmailArgs, bE as PasswordEmailFn, bF as PasswordLinkOptions, bG as PayloadTooLargeError, bH as Plugin, bI as PluginInfo, bJ as PluginTypes, bK as PreviewTarget, bL as PreviewURL, bM as QueryError, bN as ROLE_OPERATIONS, bO as RawDocument, bP as ReadOptions, bQ as RelationshipField, bR as RequestContext, R as ResolvedConfig, bS as RichTextDocument, bT as RichTextField, bU as Role, bV as RoleOperation, bW as RolePermissions, bX as Roles, bY as RoutesConfig, bZ as ScheduledPublish, b_ as SchemaError, b$ as SchemaMode, c0 as SearchAdapter, c1 as SearchEntry, c2 as SearchHits, c3 as SearchOptions, c4 as SearchQuery, c5 as SearchResults, c6 as SearchSetting, c7 as SelectField, c8 as SelectOption, c9 as Session, ca as SidebarPanel, cb as SignupArgs, cc as SignupResult, cd as SingleSignOn, ce as SlugField, cf as SlugOf, cg as SsoOutcome, ch as SsoProviderRef, ci as StorageAdapter, cj as StoredFile, ck as TRIGRAM_LIKE_MIN, cl as TelemetryConfig, cm as TextField, cn as TextareaField, co as TooManyRequestsError, cp as TypedPlugin, cq as UnauthorizedError, cr as UncountedDocs, cs as UpdateInput, ct as UpdateOptions, cu as UploadConfig, cv as UploadField, cw as UploadFromURLConfig, cx as UserIdentity, cy as ValidationError, cz as Version, cA as VersionSummary, cB as VersionsConfig, cC as WEBHOOK_EVENTS, cD as WebhookConfig, cE as WebhookEvent, cF as Where, cG as WhereOperators, cH as anyone, cI as consoleEmail, cJ as consoleLogger, cK as createEasyCMS, cL as defineConfig, cM as defineFieldType, cN as definePlugin, cO as diskStorage, cP as hasRows, cQ as isAdmin, cR as isHasMany, cS as isSignedIn, cT as isStaff, cU as isSystemAdmin, cV as jsonLogger, cW as memorySearch, cX as mimeAllowedBy, cY as rowFields, cZ as silentLogger, c_ as uniqueWithinOf } from './config-CpeC7EvC.js';
|
|
3
|
+
export { A as ADMIN_API_VERSION, a as AdminCollection, b as AdminComponentRef, c as AdminElementProps, d as AdminField, e as AdminGlobal, f as AdminLayoutNode, g as AdminNavGroup, h as AdminNavItem, i as AdminNavNode, j as AdminPageRef, k as AdminPageRoute, l as AdminSchema, m as AdminWidgetRef, S as SetFieldDetail, w as warnDeprecated } from './plugin-_XG-lqA5.js';
|
|
4
|
+
export { A as AdminBackup, a as AdminBackups, b as ApiHandlerOptions, B as BackupState, L as LoadConfigOptions, R as RestHandler, c as RestHandlerOptions, d as createApiHandler, e as createRestHandler, l as loadConfig, r as resolveConfig, s as sharedEasyCMS, f as slugify } from './handler-BpKo6gh0.js';
|
|
5
5
|
export { FieldCondition, matchesCondition } from './conditions.js';
|
|
6
6
|
|
|
7
7
|
type DeliveryKind = 'webhook' | 'email';
|
package/dist/index.js
CHANGED
package/dist/internal.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Config, Database, EasyCMS, NavGroup, CollectionConfig, ID, RawDocument, Field, ResolvedConfig, ConfigIssue } from './index.js';
|
|
2
|
-
export { c$ as API_KEYS, d0 as API_KEY_GLOBAL_OPERATIONS, d1 as API_KEY_OPERATIONS, d2 as DEFAULT_MAX_VERSIONS, d3 as DEFAULT_PASSWORD_EMAILS, d4 as FIELD_TYPE_BASES, d5 as FOLDER_LEVELS, d6 as MediaFolders, d7 as SSO_COOKIE, ck as TRIGRAM_LIKE_MIN,
|
|
3
|
-
export { C as CONFIG_FILE_NAMES, g as CSRF_COOKIE, h as CSRF_HEADER, D as DEFAULT_ADMIN_PATH, i as DEFAULT_API_PATH, j as DEFAULT_MAX_FILE_SIZE, k as DEFAULT_TOKEN_EXPIRATION, m as applyDefaults, n as applyPlugins, o as createRootEndpointHandler, p as decryptBackup, q as fillMissing, t as findConfigFile, u as forwardedClientIp, v as generateSlugs, w as importConfig, x as isEmail, y as mergeForUpdate, z as parseId, E as platformClientIp, F as readCookie, G as validateFields, H as writeBackupFile } from './handler-
|
|
2
|
+
export { c$ as API_KEYS, d0 as API_KEY_GLOBAL_OPERATIONS, d1 as API_KEY_OPERATIONS, d2 as DEFAULT_MAX_VERSIONS, d3 as DEFAULT_PASSWORD_EMAILS, d4 as FIELD_TYPE_BASES, d5 as FOLDER_LEVELS, d6 as MediaFolders, d7 as SSO_COOKIE, d8 as Secrets, ck as TRIGRAM_LIKE_MIN, d9 as codeOfStatus, cP as hasRows, cR as isHasMany, da as isJsonLogger, db as keyAllows, dc as logFormat, cX as mimeAllowedBy, cY as rowFields, dd as secretsOf, c_ as uniqueWithinOf } from './config-CpeC7EvC.js';
|
|
3
|
+
export { C as CONFIG_FILE_NAMES, g as CSRF_COOKIE, h as CSRF_HEADER, D as DEFAULT_ADMIN_PATH, i as DEFAULT_API_PATH, j as DEFAULT_MAX_FILE_SIZE, k as DEFAULT_TOKEN_EXPIRATION, m as applyDefaults, n as applyPlugins, o as createRootEndpointHandler, p as decryptBackup, q as fillMissing, t as findConfigFile, u as forwardedClientIp, v as generateSlugs, w as importConfig, x as isEmail, y as mergeForUpdate, z as parseId, E as platformClientIp, F as readCookie, G as validateFields, H as writeBackupFile } from './handler-BpKo6gh0.js';
|
|
4
4
|
export { conditionIssues } from './conditions.js';
|
|
5
5
|
|
|
6
6
|
/** The session cookie the REST API sets at login. */
|
|
@@ -112,7 +112,7 @@ declare function formToken(secret: string, purpose: string, now?: number): strin
|
|
|
112
112
|
* Checks a token: `ok` when the form was loaded at least `minTime` ms ago (people take a few
|
|
113
113
|
* seconds; bots don't) and less than a day ago.
|
|
114
114
|
*/
|
|
115
|
-
declare function checkFormToken(
|
|
115
|
+
declare function checkFormToken(secrets: string | readonly string[], purpose: string, token: unknown, minTime: number, now?: number): 'ok' | 'invalid' | 'too-fast' | 'expired';
|
|
116
116
|
/**
|
|
117
117
|
* Rate-limit keys for `subject` (e.g. an IP and a form) in the current and previous window of
|
|
118
118
|
* `window` seconds. A hash with the window in it: no IP is kept, and keys from different
|
package/dist/internal.js
CHANGED
|
@@ -52,12 +52,13 @@ import {
|
|
|
52
52
|
rateKeys,
|
|
53
53
|
readCookie,
|
|
54
54
|
resolveAdminModule,
|
|
55
|
+
secretsOf,
|
|
55
56
|
validateConfig,
|
|
56
57
|
validateFields,
|
|
57
58
|
verifyPassword,
|
|
58
59
|
verifyTurnstile,
|
|
59
60
|
writeBackupFile
|
|
60
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-NTAFZ4M6.js";
|
|
61
62
|
import {
|
|
62
63
|
conditionIssues
|
|
63
64
|
} from "./chunk-U266LV4M.js";
|
|
@@ -311,6 +312,7 @@ export {
|
|
|
311
312
|
readCookie,
|
|
312
313
|
resolveAdminModule,
|
|
313
314
|
rowFields,
|
|
315
|
+
secretsOf,
|
|
314
316
|
singularize,
|
|
315
317
|
sniffMimeType,
|
|
316
318
|
uniqueWithinOf,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { bh as Label, F as Field, I as ID, o as AdminLocale, x as AdminSwitcher, ch as SsoProviderRef } from './config-
|
|
1
|
+
import { bh as Label, F as Field, I as ID, o as AdminLocale, x as AdminSwitcher, ch as SsoProviderRef } from './config-CpeC7EvC.js';
|
|
2
2
|
import { FieldCondition } from './conditions.js';
|
|
3
3
|
|
|
4
4
|
/** A Web Component from an admin module, with its `props` (plain JSON). */
|
package/dist/plugin.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { e as ADMIN_ICONS, k as AdminComponent, n as AdminIcon, $ as AuthUser, ac as CliCommand, ad as CollectionAccess, af as CollectionConfig, C as Config, al as ConfigError, at as DashboardWidget, aD as EasyCMSError, aH as Endpoint, aI as EndpointRequest, aJ as ErrorCode, F as Field, aL as FieldAccess, a as FieldError, aQ as FieldTypeBase, aR as FieldTypeDefinition, aS as FieldTypeValidateContext, b2 as ForbiddenError, b4 as GlobalConfig, I as ID, be as JobConfig, bh as Label, bu as NavGroup, bv as NotFoundError, bx as OnRequest, by as OnRequestArgs, bB as PLUGIN_API_VERSION, bG as PayloadTooLargeError, bH as Plugin, bI as PluginInfo, bJ as PluginTypes, bM as QueryError, bR as RequestContext, co as TooManyRequestsError, cp as TypedPlugin, cq as UnauthorizedError, cy as ValidationError, cF as Where, cM as defineFieldType, cN as definePlugin } from './config-
|
|
2
|
-
export { A as ADMIN_API_VERSION, c as AdminElementProps, k as AdminPageRoute, S as SetFieldDetail, w as warnDeprecated } from './plugin-
|
|
1
|
+
export { e as ADMIN_ICONS, k as AdminComponent, n as AdminIcon, $ as AuthUser, ac as CliCommand, ad as CollectionAccess, af as CollectionConfig, C as Config, al as ConfigError, at as DashboardWidget, aD as EasyCMSError, aH as Endpoint, aI as EndpointRequest, aJ as ErrorCode, F as Field, aL as FieldAccess, a as FieldError, aQ as FieldTypeBase, aR as FieldTypeDefinition, aS as FieldTypeValidateContext, b2 as ForbiddenError, b4 as GlobalConfig, I as ID, be as JobConfig, bh as Label, bu as NavGroup, bv as NotFoundError, bx as OnRequest, by as OnRequestArgs, bB as PLUGIN_API_VERSION, bG as PayloadTooLargeError, bH as Plugin, bI as PluginInfo, bJ as PluginTypes, bM as QueryError, bR as RequestContext, co as TooManyRequestsError, cp as TypedPlugin, cq as UnauthorizedError, cy as ValidationError, cF as Where, cM as defineFieldType, cN as definePlugin } from './config-CpeC7EvC.js';
|
|
2
|
+
export { A as ADMIN_API_VERSION, c as AdminElementProps, k as AdminPageRoute, S as SetFieldDetail, w as warnDeprecated } from './plugin-_XG-lqA5.js';
|
|
3
3
|
import './conditions.js';
|