@plank-cms/plank 0.13.0 → 0.14.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/dist/admin/assets/index-BJbRJ4YN.js +222 -0
- package/dist/admin/assets/index-BmcINqbt.css +2 -0
- package/dist/admin/index.html +2 -2
- package/dist/index.js +4 -2
- package/dist/migrations/024_users_two_factor.sql +4 -0
- package/dist/migrations/025_auth_security.sql +13 -0
- package/dist/{server-LQ6BBDAE.js → server-CKAS7YSX.js} +1880 -182
- package/package.json +4 -4
- package/dist/admin/assets/index-Coy7xlHI.css +0 -2
- package/dist/admin/assets/index-DVrMX0qP.js +0 -203
|
@@ -67,7 +67,7 @@ async function ensureMigrationsTable(client) {
|
|
|
67
67
|
}
|
|
68
68
|
async function appliedMigrations(client) {
|
|
69
69
|
const { rows } = await client.query("SELECT filename FROM plank_migrations ORDER BY filename");
|
|
70
|
-
return new Set(rows.map((
|
|
70
|
+
return new Set(rows.map((r2) => r2.filename));
|
|
71
71
|
}
|
|
72
72
|
async function seedDefaultRoles(client) {
|
|
73
73
|
const { rows } = await client.query("SELECT COUNT(*) as count FROM plank_roles");
|
|
@@ -83,7 +83,7 @@ async function migrate() {
|
|
|
83
83
|
try {
|
|
84
84
|
await client.query("BEGIN");
|
|
85
85
|
await ensureMigrationsTable(client);
|
|
86
|
-
const files = (await readdir(MIGRATIONS_DIR)).filter((
|
|
86
|
+
const files = (await readdir(MIGRATIONS_DIR)).filter((f2) => f2.endsWith(".sql")).sort();
|
|
87
87
|
const applied = await appliedMigrations(client);
|
|
88
88
|
for (const file of files) {
|
|
89
89
|
if (applied.has(file))
|
|
@@ -270,7 +270,7 @@ function relationSignature(field) {
|
|
|
270
270
|
async function createTable(contentType) {
|
|
271
271
|
assertSafeIdentifier(contentType.tableName);
|
|
272
272
|
const quotedTableName = quoteIdentifier(contentType.tableName);
|
|
273
|
-
const columnFields = contentType.fields.filter((
|
|
273
|
+
const columnFields = contentType.fields.filter((f2) => !isVirtualRelation(f2));
|
|
274
274
|
const columns = columnFields.map(buildColumnDef).filter(Boolean);
|
|
275
275
|
const sql = [
|
|
276
276
|
`CREATE TABLE IF NOT EXISTS ${quotedTableName} (`,
|
|
@@ -300,8 +300,8 @@ async function createTable(contentType) {
|
|
|
300
300
|
async function syncTable(next, prev) {
|
|
301
301
|
assertSafeIdentifier(next.tableName);
|
|
302
302
|
const quotedTableName = quoteIdentifier(next.tableName);
|
|
303
|
-
const prevFields = new Map(prev.fields.map((
|
|
304
|
-
const nextFields = new Map(next.fields.map((
|
|
303
|
+
const prevFields = new Map(prev.fields.map((f2) => [f2.name, f2]));
|
|
304
|
+
const nextFields = new Map(next.fields.map((f2) => [f2.name, f2]));
|
|
305
305
|
const statements = [];
|
|
306
306
|
const junctionOps = [];
|
|
307
307
|
for (const [name, field] of nextFields) {
|
|
@@ -390,7 +390,7 @@ async function syncAllTables() {
|
|
|
390
390
|
assertSafeIdentifier(ct.tableName);
|
|
391
391
|
const quotedTableName = quoteIdentifier(ct.tableName);
|
|
392
392
|
const { rows } = await pool_default.query(`SELECT column_name FROM information_schema.columns WHERE table_name = $1 AND table_schema = 'public'`, [ct.tableName]);
|
|
393
|
-
const existingColumns = new Set(rows.map((
|
|
393
|
+
const existingColumns = new Set(rows.map((r2) => r2.column_name));
|
|
394
394
|
if (!existingColumns.has("localized")) {
|
|
395
395
|
try {
|
|
396
396
|
await pool_default.query(`ALTER TABLE ${quotedTableName} ADD COLUMN IF NOT EXISTS localized JSONB`);
|
|
@@ -435,9 +435,9 @@ function validateNavigationItems(value, fieldName, errors, path = fieldName, dep
|
|
|
435
435
|
if (value.length > MAX_NAVIGATION_ITEMS_PER_LEVEL) {
|
|
436
436
|
errors.push(`Field "${path}" cannot have more than ${MAX_NAVIGATION_ITEMS_PER_LEVEL} items per level`);
|
|
437
437
|
}
|
|
438
|
-
for (let
|
|
439
|
-
const item = value[
|
|
440
|
-
const itemPath = `${path}[${
|
|
438
|
+
for (let i2 = 0; i2 < value.length; i2++) {
|
|
439
|
+
const item = value[i2];
|
|
440
|
+
const itemPath = `${path}[${i2}]`;
|
|
441
441
|
if (typeof item !== "object" || item === null) {
|
|
442
442
|
errors.push(`Field "${itemPath}" must be an object`);
|
|
443
443
|
continue;
|
|
@@ -495,7 +495,7 @@ function validate(contentType, payload) {
|
|
|
495
495
|
}
|
|
496
496
|
break;
|
|
497
497
|
case "media-gallery":
|
|
498
|
-
if (!Array.isArray(value) || value.some((
|
|
498
|
+
if (!Array.isArray(value) || value.some((v3) => typeof v3 !== "string" || !v3.trim())) {
|
|
499
499
|
errors.push(`Field "${field.name}" must be an array of media IDs`);
|
|
500
500
|
} else if (field.required && value.length === 0) {
|
|
501
501
|
errors.push(`Field "${field.name}" is required`);
|
|
@@ -506,7 +506,7 @@ function validate(contentType, payload) {
|
|
|
506
506
|
if (rt === "one-to-many")
|
|
507
507
|
break;
|
|
508
508
|
if (rt === "many-to-many") {
|
|
509
|
-
if (!Array.isArray(value) || value.some((
|
|
509
|
+
if (!Array.isArray(value) || value.some((v3) => typeof v3 !== "string" || !v3.trim())) {
|
|
510
510
|
errors.push(`Field "${field.name}" must be an array of IDs`);
|
|
511
511
|
} else if (field.required && value.length === 0) {
|
|
512
512
|
errors.push(`Field "${field.name}" is required`);
|
|
@@ -524,17 +524,17 @@ function validate(contentType, payload) {
|
|
|
524
524
|
} else if (field.required && value.length === 0) {
|
|
525
525
|
errors.push(`Field "${field.name}" is required`);
|
|
526
526
|
} else if (field.arrayFields && field.arrayFields.length > 0) {
|
|
527
|
-
for (let
|
|
528
|
-
const item = value[
|
|
527
|
+
for (let i2 = 0; i2 < value.length; i2++) {
|
|
528
|
+
const item = value[i2];
|
|
529
529
|
if (typeof item !== "object" || item === null) {
|
|
530
|
-
errors.push(`Field "${field.name}[${
|
|
530
|
+
errors.push(`Field "${field.name}[${i2}]" must be an object`);
|
|
531
531
|
continue;
|
|
532
532
|
}
|
|
533
533
|
for (const subField of field.arrayFields) {
|
|
534
534
|
const subValue = item[subField.name];
|
|
535
535
|
const subEmpty = subValue === void 0 || subValue === null || subValue === "";
|
|
536
536
|
if (subField.required && subEmpty) {
|
|
537
|
-
errors.push(`Field "${field.name}[${
|
|
537
|
+
errors.push(`Field "${field.name}[${i2}].${subField.name}" is required`);
|
|
538
538
|
}
|
|
539
539
|
}
|
|
540
540
|
}
|
|
@@ -557,7 +557,7 @@ function validate(contentType, payload) {
|
|
|
557
557
|
import express from "express";
|
|
558
558
|
import cors from "cors";
|
|
559
559
|
import helmet from "helmet";
|
|
560
|
-
import { join as
|
|
560
|
+
import { join as join4, dirname as dirname2 } from "path";
|
|
561
561
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
562
562
|
|
|
563
563
|
// ../core/dist/routes/auth.js
|
|
@@ -566,23 +566,1453 @@ import { Router } from "express";
|
|
|
566
566
|
// ../core/dist/controllers/auth.js
|
|
567
567
|
import bcrypt from "bcryptjs";
|
|
568
568
|
import jwt from "jsonwebtoken";
|
|
569
|
+
|
|
570
|
+
// ../../node_modules/.pnpm/@otplib+core@13.4.0/node_modules/@otplib/core/dist/index.js
|
|
571
|
+
var i = class extends Error {
|
|
572
|
+
constructor(e, t2) {
|
|
573
|
+
super(e, t2), this.name = "OTPError";
|
|
574
|
+
}
|
|
575
|
+
};
|
|
576
|
+
var x = class extends i {
|
|
577
|
+
constructor(e) {
|
|
578
|
+
super(e), this.name = "SecretError";
|
|
579
|
+
}
|
|
580
|
+
};
|
|
581
|
+
var h = class extends x {
|
|
582
|
+
constructor(e, t2) {
|
|
583
|
+
super(`Secret must be at least ${e} bytes (${e * 8} bits), got ${t2} bytes`), this.name = "SecretTooShortError";
|
|
584
|
+
}
|
|
585
|
+
};
|
|
586
|
+
var P = class extends x {
|
|
587
|
+
constructor(e, t2) {
|
|
588
|
+
super(`Secret must not exceed ${e} bytes, got ${t2} bytes`), this.name = "SecretTooLongError";
|
|
589
|
+
}
|
|
590
|
+
};
|
|
591
|
+
var m = class extends i {
|
|
592
|
+
constructor(e) {
|
|
593
|
+
super(e), this.name = "CounterError";
|
|
594
|
+
}
|
|
595
|
+
};
|
|
596
|
+
var O = class extends m {
|
|
597
|
+
constructor() {
|
|
598
|
+
super("Counter must be non-negative"), this.name = "CounterNegativeError";
|
|
599
|
+
}
|
|
600
|
+
};
|
|
601
|
+
var T = class extends m {
|
|
602
|
+
constructor() {
|
|
603
|
+
super("Counter exceeds maximum safe integer value"), this.name = "CounterOverflowError";
|
|
604
|
+
}
|
|
605
|
+
};
|
|
606
|
+
var b = class extends m {
|
|
607
|
+
constructor() {
|
|
608
|
+
super("Counter must be a finite integer"), this.name = "CounterNotIntegerError";
|
|
609
|
+
}
|
|
610
|
+
};
|
|
611
|
+
var A = class extends i {
|
|
612
|
+
constructor(e) {
|
|
613
|
+
super(e), this.name = "TimeError";
|
|
614
|
+
}
|
|
615
|
+
};
|
|
616
|
+
var C = class extends A {
|
|
617
|
+
constructor() {
|
|
618
|
+
super("Time must be non-negative"), this.name = "TimeNegativeError";
|
|
619
|
+
}
|
|
620
|
+
};
|
|
621
|
+
var S = class extends A {
|
|
622
|
+
constructor() {
|
|
623
|
+
super("Time must be a finite number"), this.name = "TimeNotFiniteError";
|
|
624
|
+
}
|
|
625
|
+
};
|
|
626
|
+
var B = class extends i {
|
|
627
|
+
constructor(e) {
|
|
628
|
+
super(e), this.name = "PeriodError";
|
|
629
|
+
}
|
|
630
|
+
};
|
|
631
|
+
var w = class extends B {
|
|
632
|
+
constructor(e) {
|
|
633
|
+
super(`Period must be at least ${e} second(s)`), this.name = "PeriodTooSmallError";
|
|
634
|
+
}
|
|
635
|
+
};
|
|
636
|
+
var _ = class extends B {
|
|
637
|
+
constructor(e) {
|
|
638
|
+
super(`Period must not exceed ${e} seconds`), this.name = "PeriodTooLargeError";
|
|
639
|
+
}
|
|
640
|
+
};
|
|
641
|
+
var R = class extends i {
|
|
642
|
+
constructor(e) {
|
|
643
|
+
super(e), this.name = "TokenError";
|
|
644
|
+
}
|
|
645
|
+
};
|
|
646
|
+
var I = class extends R {
|
|
647
|
+
constructor(e, t2) {
|
|
648
|
+
super(`Token must be ${e} digits, got ${t2}`), this.name = "TokenLengthError";
|
|
649
|
+
}
|
|
650
|
+
};
|
|
651
|
+
var M = class extends R {
|
|
652
|
+
constructor() {
|
|
653
|
+
super("Token must contain only digits"), this.name = "TokenFormatError";
|
|
654
|
+
}
|
|
655
|
+
};
|
|
656
|
+
var N = class extends i {
|
|
657
|
+
constructor(e, t2) {
|
|
658
|
+
super(e, t2), this.name = "CryptoError";
|
|
659
|
+
}
|
|
660
|
+
};
|
|
661
|
+
var c = class extends N {
|
|
662
|
+
constructor(e, t2) {
|
|
663
|
+
super(`HMAC computation failed: ${e}`, t2), this.name = "HMACError";
|
|
664
|
+
}
|
|
665
|
+
};
|
|
666
|
+
var v = class extends N {
|
|
667
|
+
constructor(e, t2) {
|
|
668
|
+
super(`Random byte generation failed: ${e}`, t2), this.name = "RandomBytesError";
|
|
669
|
+
}
|
|
670
|
+
};
|
|
671
|
+
var g = class extends i {
|
|
672
|
+
constructor(e) {
|
|
673
|
+
super(e), this.name = "CounterToleranceError";
|
|
674
|
+
}
|
|
675
|
+
};
|
|
676
|
+
var U = class extends g {
|
|
677
|
+
constructor(e, t2) {
|
|
678
|
+
super(`Counter tolerance validation failed: total checks (${t2}) exceeds MAX_WINDOW (${e})`), this.name = "CounterToleranceTooLargeError";
|
|
679
|
+
}
|
|
680
|
+
};
|
|
681
|
+
var X = class extends g {
|
|
682
|
+
constructor() {
|
|
683
|
+
super("Counter tolerance cannot contain negative values"), this.name = "CounterToleranceNegativeError";
|
|
684
|
+
}
|
|
685
|
+
};
|
|
686
|
+
var E = class extends i {
|
|
687
|
+
constructor(e) {
|
|
688
|
+
super(e), this.name = "EpochToleranceError";
|
|
689
|
+
}
|
|
690
|
+
};
|
|
691
|
+
var k = class extends E {
|
|
692
|
+
constructor() {
|
|
693
|
+
super("Epoch tolerance cannot contain negative values"), this.name = "EpochToleranceNegativeError";
|
|
694
|
+
}
|
|
695
|
+
};
|
|
696
|
+
var q = class extends E {
|
|
697
|
+
constructor(e, t2) {
|
|
698
|
+
super(`Epoch tolerance must not exceed ${e} seconds, got ${t2}. Large tolerances can cause performance issues.`), this.name = "EpochToleranceTooLargeError";
|
|
699
|
+
}
|
|
700
|
+
};
|
|
701
|
+
var G = class extends i {
|
|
702
|
+
constructor(e) {
|
|
703
|
+
super(e), this.name = "PluginError";
|
|
704
|
+
}
|
|
705
|
+
};
|
|
706
|
+
var Y = class extends G {
|
|
707
|
+
constructor() {
|
|
708
|
+
super("Crypto plugin is required."), this.name = "CryptoPluginMissingError";
|
|
709
|
+
}
|
|
710
|
+
};
|
|
711
|
+
var L = class extends G {
|
|
712
|
+
constructor() {
|
|
713
|
+
super("Base32 plugin is required."), this.name = "Base32PluginMissingError";
|
|
714
|
+
}
|
|
715
|
+
};
|
|
716
|
+
var a = class extends i {
|
|
717
|
+
constructor(e) {
|
|
718
|
+
super(e), this.name = "ConfigurationError";
|
|
719
|
+
}
|
|
720
|
+
};
|
|
721
|
+
var W = class extends a {
|
|
722
|
+
constructor() {
|
|
723
|
+
super("Secret is required. Use generateSecret() to create one, or provide via { secret: 'YOUR_BASE32_SECRET' }"), this.name = "SecretMissingError";
|
|
724
|
+
}
|
|
725
|
+
};
|
|
726
|
+
var f = class extends i {
|
|
727
|
+
constructor(e) {
|
|
728
|
+
super(e), this.name = "AfterTimeStepError";
|
|
729
|
+
}
|
|
730
|
+
};
|
|
731
|
+
var J = class extends f {
|
|
732
|
+
constructor() {
|
|
733
|
+
super("afterTimeStep must be >= 0"), this.name = "AfterTimeStepNegativeError";
|
|
734
|
+
}
|
|
735
|
+
};
|
|
736
|
+
var Q = class extends f {
|
|
737
|
+
constructor() {
|
|
738
|
+
super("Invalid afterTimeStep: non-integer value"), this.name = "AfterTimeStepNotIntegerError";
|
|
739
|
+
}
|
|
740
|
+
};
|
|
741
|
+
var Z = class extends f {
|
|
742
|
+
constructor() {
|
|
743
|
+
super("Invalid afterTimeStep: cannot be greater than current time step plus window"), this.name = "AfterTimeStepRangeExceededError";
|
|
744
|
+
}
|
|
745
|
+
};
|
|
746
|
+
var yr = new TextEncoder();
|
|
747
|
+
var xr = new TextDecoder();
|
|
748
|
+
var or = 16;
|
|
749
|
+
var sr = 64;
|
|
750
|
+
var ir = 20;
|
|
751
|
+
var ar = 1;
|
|
752
|
+
var ur = 3600;
|
|
753
|
+
var cr = 30;
|
|
754
|
+
var pr = Number.MAX_SAFE_INTEGER;
|
|
755
|
+
var lr = 99;
|
|
756
|
+
var er = /* @__PURE__ */ Symbol("otplib.guardrails.override");
|
|
757
|
+
function y(r2, e, t2) {
|
|
758
|
+
if (typeof e != "number" || !Number.isSafeInteger(e)) throw new a(`Guardrail '${r2}' must be a safe integer`);
|
|
759
|
+
if (e < t2) throw new a(`Guardrail '${r2}' must be >= ${t2}`);
|
|
760
|
+
}
|
|
761
|
+
var d = Object.freeze({ MIN_SECRET_BYTES: or, MAX_SECRET_BYTES: sr, MIN_PERIOD: ar, MAX_PERIOD: ur, MAX_COUNTER: pr, MAX_WINDOW: lr, [er]: false });
|
|
762
|
+
function hr(r2) {
|
|
763
|
+
if (!r2) return d;
|
|
764
|
+
r2.MIN_SECRET_BYTES !== void 0 && y("MIN_SECRET_BYTES", r2.MIN_SECRET_BYTES, 1), r2.MAX_SECRET_BYTES !== void 0 && y("MAX_SECRET_BYTES", r2.MAX_SECRET_BYTES, 1), r2.MIN_PERIOD !== void 0 && y("MIN_PERIOD", r2.MIN_PERIOD, 1), r2.MAX_PERIOD !== void 0 && y("MAX_PERIOD", r2.MAX_PERIOD, 1), r2.MAX_COUNTER !== void 0 && y("MAX_COUNTER", r2.MAX_COUNTER, 0), r2.MAX_WINDOW !== void 0 && y("MAX_WINDOW", r2.MAX_WINDOW, 1);
|
|
765
|
+
let e = { ...d, ...r2 };
|
|
766
|
+
if (e.MIN_SECRET_BYTES > e.MAX_SECRET_BYTES) throw new a("Guardrail 'MIN_SECRET_BYTES' must be <= 'MAX_SECRET_BYTES'");
|
|
767
|
+
if (e.MIN_PERIOD > e.MAX_PERIOD) throw new a("Guardrail 'MIN_PERIOD' must be <= 'MAX_PERIOD'");
|
|
768
|
+
return Object.freeze({ ...e, [er]: true });
|
|
769
|
+
}
|
|
770
|
+
function Or(r2, e = d) {
|
|
771
|
+
if (r2.length < e.MIN_SECRET_BYTES) throw new h(e.MIN_SECRET_BYTES, r2.length);
|
|
772
|
+
if (r2.length > e.MAX_SECRET_BYTES) throw new P(e.MAX_SECRET_BYTES, r2.length);
|
|
773
|
+
}
|
|
774
|
+
function br(r2, e = d) {
|
|
775
|
+
if (typeof r2 == "number") {
|
|
776
|
+
if (!Number.isFinite(r2) || !Number.isInteger(r2)) throw new b();
|
|
777
|
+
if (!Number.isSafeInteger(r2)) throw new T();
|
|
778
|
+
}
|
|
779
|
+
let t2 = typeof r2 == "bigint" ? r2 : BigInt(r2);
|
|
780
|
+
if (t2 < 0n) throw new O();
|
|
781
|
+
if (t2 > BigInt(e.MAX_COUNTER)) throw new T();
|
|
782
|
+
}
|
|
783
|
+
function Ar(r2) {
|
|
784
|
+
if (!Number.isFinite(r2)) throw new S();
|
|
785
|
+
if (r2 < 0) throw new C();
|
|
786
|
+
}
|
|
787
|
+
function Cr(r2, e = d) {
|
|
788
|
+
if (!Number.isInteger(r2) || r2 < e.MIN_PERIOD) throw new w(e.MIN_PERIOD);
|
|
789
|
+
if (r2 > e.MAX_PERIOD) throw new _(e.MAX_PERIOD);
|
|
790
|
+
}
|
|
791
|
+
function Sr(r2, e) {
|
|
792
|
+
if (r2.length !== e) throw new I(e, r2.length);
|
|
793
|
+
if (!/^\d+$/.test(r2)) throw new M();
|
|
794
|
+
}
|
|
795
|
+
function Br(r2, e = d) {
|
|
796
|
+
let [t2, o] = Er(r2);
|
|
797
|
+
if (!Number.isSafeInteger(t2) || !Number.isSafeInteger(o)) throw new g("Counter tolerance values must be safe integers");
|
|
798
|
+
if (t2 < 0 || o < 0) throw new X();
|
|
799
|
+
let n = t2 + o + 1;
|
|
800
|
+
if (n > e.MAX_WINDOW) throw new U(e.MAX_WINDOW, n);
|
|
801
|
+
}
|
|
802
|
+
function wr(r2, e = cr, t2 = d) {
|
|
803
|
+
let [o, n] = Array.isArray(r2) ? r2 : [r2, r2];
|
|
804
|
+
if (!Number.isSafeInteger(o) || !Number.isSafeInteger(n)) throw new E("Epoch tolerance values must be safe integers");
|
|
805
|
+
if (o < 0 || n < 0) throw new k();
|
|
806
|
+
let s = (t2.MAX_WINDOW - 1) * e, u = o + n;
|
|
807
|
+
if (u > s) throw new q(s, u);
|
|
808
|
+
}
|
|
809
|
+
function _r(r2) {
|
|
810
|
+
let e = typeof r2 == "bigint" ? r2 : BigInt(r2), t2 = new ArrayBuffer(8);
|
|
811
|
+
return new DataView(t2).setBigUint64(0, e, false), new Uint8Array(t2);
|
|
812
|
+
}
|
|
813
|
+
function Rr(r2) {
|
|
814
|
+
let e = r2[r2.length - 1] & 15;
|
|
815
|
+
return (r2[e] & 127) << 24 | r2[e + 1] << 16 | r2[e + 2] << 8 | r2[e + 3];
|
|
816
|
+
}
|
|
817
|
+
function Ir(r2, e) {
|
|
818
|
+
let t2 = 10 ** e;
|
|
819
|
+
return (r2 % t2).toString().padStart(e, "0");
|
|
820
|
+
}
|
|
821
|
+
function gr(r2, e) {
|
|
822
|
+
return r2.length === e.length;
|
|
823
|
+
}
|
|
824
|
+
function tr(r2, e) {
|
|
825
|
+
let t2 = rr(r2), o = rr(e);
|
|
826
|
+
if (!gr(t2, o)) return false;
|
|
827
|
+
let n = 0;
|
|
828
|
+
for (let s = 0; s < t2.length; s++) n |= t2[s] ^ o[s];
|
|
829
|
+
return n === 0;
|
|
830
|
+
}
|
|
831
|
+
function rr(r2) {
|
|
832
|
+
return typeof r2 == "string" ? yr.encode(r2) : r2;
|
|
833
|
+
}
|
|
834
|
+
function vr(r2, e) {
|
|
835
|
+
return typeof r2 == "string" ? (nr(e), e.decode(r2)) : r2;
|
|
836
|
+
}
|
|
837
|
+
function Dr(r2) {
|
|
838
|
+
let { crypto: e, base32: t2, length: o = ir } = r2;
|
|
839
|
+
dr(e), nr(t2);
|
|
840
|
+
let n = e.randomBytes(o);
|
|
841
|
+
return t2.encode(n, { padding: false });
|
|
842
|
+
}
|
|
843
|
+
function Er(r2 = 0) {
|
|
844
|
+
return Array.isArray(r2) ? r2 : [0, r2];
|
|
845
|
+
}
|
|
846
|
+
function Ur(r2 = 0) {
|
|
847
|
+
return Array.isArray(r2) ? r2 : [r2, r2];
|
|
848
|
+
}
|
|
849
|
+
function dr(r2) {
|
|
850
|
+
if (!r2) throw new Y();
|
|
851
|
+
}
|
|
852
|
+
function nr(r2) {
|
|
853
|
+
if (!r2) throw new L();
|
|
854
|
+
}
|
|
855
|
+
function Xr(r2) {
|
|
856
|
+
if (!r2) throw new W();
|
|
857
|
+
}
|
|
858
|
+
var K = class {
|
|
859
|
+
constructor(e) {
|
|
860
|
+
this.crypto = e;
|
|
861
|
+
}
|
|
862
|
+
get plugin() {
|
|
863
|
+
return this.crypto;
|
|
864
|
+
}
|
|
865
|
+
async hmac(e, t2, o) {
|
|
866
|
+
try {
|
|
867
|
+
let n = this.crypto.hmac(e, t2, o);
|
|
868
|
+
return n instanceof Promise ? await n : n;
|
|
869
|
+
} catch (n) {
|
|
870
|
+
let s = n instanceof Error ? n.message : String(n);
|
|
871
|
+
throw new c(s, { cause: n });
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
hmacSync(e, t2, o) {
|
|
875
|
+
try {
|
|
876
|
+
let n = this.crypto.hmac(e, t2, o);
|
|
877
|
+
if (n instanceof Promise) throw new c("Crypto plugin does not support synchronous HMAC operations");
|
|
878
|
+
return n;
|
|
879
|
+
} catch (n) {
|
|
880
|
+
if (n instanceof c) throw n;
|
|
881
|
+
let s = n instanceof Error ? n.message : String(n);
|
|
882
|
+
throw new c(s, { cause: n });
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
randomBytes(e) {
|
|
886
|
+
try {
|
|
887
|
+
return this.crypto.randomBytes(e);
|
|
888
|
+
} catch (t2) {
|
|
889
|
+
let o = t2 instanceof Error ? t2.message : String(t2);
|
|
890
|
+
throw new v(o, { cause: t2 });
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
};
|
|
894
|
+
function Wr(r2) {
|
|
895
|
+
return new K(r2);
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
// ../../node_modules/.pnpm/@otplib+uri@13.4.0/node_modules/@otplib/uri/dist/index.js
|
|
899
|
+
function m2(r2) {
|
|
900
|
+
let { type: e, label: s, params: t2 } = r2, i2 = s.split(":").map((c3) => encodeURIComponent(c3)).join(":"), o = `otpauth://${e}/${i2}?`, n = [];
|
|
901
|
+
return t2.secret && n.push(`secret=${encodeURIComponent(t2.secret)}`), t2.issuer && n.push(`issuer=${encodeURIComponent(t2.issuer)}`), t2.algorithm && t2.algorithm !== "sha1" && n.push(`algorithm=${t2.algorithm.toUpperCase()}`), t2.digits && t2.digits !== 6 && n.push(`digits=${t2.digits}`), e === "hotp" && t2.counter !== void 0 && n.push(`counter=${t2.counter}`), e === "totp" && t2.period !== void 0 && t2.period !== 30 && n.push(`period=${t2.period}`), o += n.join("&"), o;
|
|
902
|
+
}
|
|
903
|
+
function x2(r2) {
|
|
904
|
+
let { issuer: e, label: s, secret: t2, algorithm: i2 = "sha1", digits: o = 6, period: n = 30 } = r2, c3 = e ? `${e}:${s}` : s;
|
|
905
|
+
return m2({ type: "totp", label: c3, params: { secret: t2, issuer: e, algorithm: i2, digits: o, period: n } });
|
|
906
|
+
}
|
|
907
|
+
function U2(r2) {
|
|
908
|
+
let { issuer: e, label: s, secret: t2, counter: i2 = 0, algorithm: o = "sha1", digits: n = 6 } = r2, c3 = e ? `${e}:${s}` : s;
|
|
909
|
+
return m2({ type: "hotp", label: c3, params: { secret: t2, issuer: e, algorithm: o, digits: n, counter: i2 } });
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
// ../../node_modules/.pnpm/@otplib+hotp@13.4.0/node_modules/@otplib/hotp/dist/index.js
|
|
913
|
+
function v2(u) {
|
|
914
|
+
let { secret: t2, counter: e, algorithm: r2 = "sha1", digits: i2 = 6, crypto: n, base32: o, guardrails: a2, hooks: s } = u;
|
|
915
|
+
Xr(t2), dr(n);
|
|
916
|
+
let c3 = vr(t2, o);
|
|
917
|
+
Or(c3, a2), br(e, a2);
|
|
918
|
+
let p = Wr(n), l2 = _r(e);
|
|
919
|
+
return { ctx: p, algorithm: r2, digits: i2, secretBytes: c3, counterBytes: l2, hooks: s };
|
|
920
|
+
}
|
|
921
|
+
function F(u) {
|
|
922
|
+
let { ctx: t2, algorithm: e, digits: r2, secretBytes: i2, counterBytes: n, hooks: o } = v2(u), a2 = t2.hmacSync(e, i2, n), s = o?.truncateDigest ? o.truncateDigest(a2) : Rr(a2);
|
|
923
|
+
return o?.encodeToken ? o.encodeToken(s, r2) : Ir(s, r2);
|
|
924
|
+
}
|
|
925
|
+
function G2(u) {
|
|
926
|
+
let { secret: t2, counter: e, token: r2, algorithm: i2 = "sha1", digits: n = 6, crypto: o, base32: a2, counterTolerance: s = 0, guardrails: c3 = hr(), hooks: p } = u;
|
|
927
|
+
Xr(t2), dr(o);
|
|
928
|
+
let l2 = vr(t2, a2);
|
|
929
|
+
Or(l2, c3), br(e, c3), p?.validateToken ? p.validateToken(r2, n) : Sr(r2, n), Br(s, c3);
|
|
930
|
+
let V = typeof e == "bigint" ? Number(e) : e, [f2, d4] = Er(s), R3 = f2 + d4 + 1;
|
|
931
|
+
return { token: r2, counterNum: V, past: f2, future: d4, totalChecks: R3, crypto: o, getGenerateOptions: (B2) => ({ secret: l2, counter: B2, algorithm: i2, digits: n, crypto: o, guardrails: c3, hooks: p }) };
|
|
932
|
+
}
|
|
933
|
+
function Y2(u) {
|
|
934
|
+
let { token: t2, counterNum: e, past: r2, totalChecks: i2, crypto: n, getGenerateOptions: o } = G2(u), a2 = Math.max(0, r2 - e);
|
|
935
|
+
for (let s = a2; s < i2; s++) {
|
|
936
|
+
let c3 = s - r2, p = e + c3, l2 = F(o(p));
|
|
937
|
+
if (n.constantTimeEqual(l2, t2)) return { valid: true, delta: c3 | 0 };
|
|
938
|
+
}
|
|
939
|
+
return { valid: false };
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
// ../../node_modules/.pnpm/@otplib+totp@13.4.0/node_modules/@otplib/totp/dist/index.js
|
|
943
|
+
function k2(r2) {
|
|
944
|
+
let { secret: e, epoch: n = Math.floor(Date.now() / 1e3), t0: o = 0, period: i2 = 30, algorithm: s = "sha1", digits: l2 = 6, crypto: a2, base32: u, guardrails: c3 = hr(), hooks: t2 } = r2;
|
|
945
|
+
Xr(e), dr(a2);
|
|
946
|
+
let p = vr(e, u);
|
|
947
|
+
Or(p, c3), Ar(n), Cr(i2, c3);
|
|
948
|
+
let f2 = Math.floor((n - o) / i2);
|
|
949
|
+
return { secret: p, counter: f2, algorithm: s, digits: l2, crypto: a2, guardrails: c3, hooks: t2 };
|
|
950
|
+
}
|
|
951
|
+
function Z2(r2) {
|
|
952
|
+
let e = k2(r2);
|
|
953
|
+
return F(e);
|
|
954
|
+
}
|
|
955
|
+
function _2(r2, e) {
|
|
956
|
+
if (r2 !== void 0) {
|
|
957
|
+
if (r2 < 0) throw new J();
|
|
958
|
+
if (!Number.isSafeInteger(r2)) throw new Q();
|
|
959
|
+
if (r2 > e) throw new Z();
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
function w2(r2, e) {
|
|
963
|
+
return e !== void 0 && r2 <= e;
|
|
964
|
+
}
|
|
965
|
+
function R2(r2) {
|
|
966
|
+
let { secret: e, token: n, epoch: o = Math.floor(Date.now() / 1e3), t0: i2 = 0, period: s = 30, algorithm: l2 = "sha1", digits: a2 = 6, crypto: u, base32: c3, epochTolerance: t2 = 0, afterTimeStep: p, guardrails: f2 = hr(), hooks: T3 } = r2;
|
|
967
|
+
Xr(e), dr(u);
|
|
968
|
+
let m3 = vr(e, c3);
|
|
969
|
+
Or(m3, f2), Ar(o), Cr(s, f2), T3?.validateToken ? T3.validateToken(n, a2) : Sr(n, a2), wr(t2, s, f2);
|
|
970
|
+
let M2 = Math.floor((o - i2) / s), [I3, q2] = Ur(t2), A3 = Math.max(0, Math.floor((o - I3 - i2) / s)), S2 = Math.floor((o + q2 - i2) / s);
|
|
971
|
+
return _2(p, S2), { token: n, crypto: u, minCounter: A3, maxCounter: S2, currentCounter: M2, t0: i2, period: s, afterTimeStep: p, getGenerateOptions: (D) => ({ secret: m3, epoch: D * s + i2, t0: i2, period: s, algorithm: l2, digits: a2, crypto: u, guardrails: f2, hooks: T3 }) };
|
|
972
|
+
}
|
|
973
|
+
function ie(r2) {
|
|
974
|
+
let { token: e, crypto: n, minCounter: o, maxCounter: i2, currentCounter: s, t0: l2, period: a2, afterTimeStep: u, getGenerateOptions: c3 } = R2(r2);
|
|
975
|
+
for (let t2 = o; t2 <= i2; t2++) {
|
|
976
|
+
if (w2(t2, u)) continue;
|
|
977
|
+
let p = Z2(c3(t2));
|
|
978
|
+
if (n.constantTimeEqual(p, e)) return { valid: true, delta: t2 - s, epoch: t2 * a2 + l2, timeStep: t2 };
|
|
979
|
+
}
|
|
980
|
+
return { valid: false };
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
// ../../node_modules/.pnpm/@scure+base@2.2.0/node_modules/@scure/base/index.js
|
|
984
|
+
function isBytes(a2) {
|
|
985
|
+
return a2 instanceof Uint8Array || ArrayBuffer.isView(a2) && a2.constructor.name === "Uint8Array" && "BYTES_PER_ELEMENT" in a2 && a2.BYTES_PER_ELEMENT === 1;
|
|
986
|
+
}
|
|
987
|
+
function isArrayOf(isString, arr) {
|
|
988
|
+
if (!Array.isArray(arr))
|
|
989
|
+
return false;
|
|
990
|
+
if (arr.length === 0)
|
|
991
|
+
return true;
|
|
992
|
+
if (isString) {
|
|
993
|
+
return arr.every((item) => typeof item === "string");
|
|
994
|
+
} else {
|
|
995
|
+
return arr.every((item) => Number.isSafeInteger(item));
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
function astr(label, input) {
|
|
999
|
+
if (typeof input !== "string")
|
|
1000
|
+
throw new TypeError(`${label}: string expected`);
|
|
1001
|
+
return true;
|
|
1002
|
+
}
|
|
1003
|
+
function anumber(n) {
|
|
1004
|
+
if (typeof n !== "number")
|
|
1005
|
+
throw new TypeError(`number expected, got ${typeof n}`);
|
|
1006
|
+
if (!Number.isSafeInteger(n))
|
|
1007
|
+
throw new RangeError(`invalid integer: ${n}`);
|
|
1008
|
+
}
|
|
1009
|
+
function aArr(input) {
|
|
1010
|
+
if (!Array.isArray(input))
|
|
1011
|
+
throw new TypeError("array expected");
|
|
1012
|
+
}
|
|
1013
|
+
function astrArr(label, input) {
|
|
1014
|
+
if (!isArrayOf(true, input))
|
|
1015
|
+
throw new TypeError(`${label}: array of strings expected`);
|
|
1016
|
+
}
|
|
1017
|
+
function anumArr(label, input) {
|
|
1018
|
+
if (!isArrayOf(false, input))
|
|
1019
|
+
throw new TypeError(`${label}: array of numbers expected`);
|
|
1020
|
+
}
|
|
1021
|
+
// @__NO_SIDE_EFFECTS__
|
|
1022
|
+
function chain(...args) {
|
|
1023
|
+
const id = (a2) => a2;
|
|
1024
|
+
const wrap = (a2, b3) => (c3) => a2(b3(c3));
|
|
1025
|
+
const encode = args.map((x4) => x4.encode).reduceRight(wrap, id);
|
|
1026
|
+
const decode = args.map((x4) => x4.decode).reduce(wrap, id);
|
|
1027
|
+
return { encode, decode };
|
|
1028
|
+
}
|
|
1029
|
+
// @__NO_SIDE_EFFECTS__
|
|
1030
|
+
function alphabet(letters) {
|
|
1031
|
+
const lettersA = typeof letters === "string" ? letters.split("") : letters;
|
|
1032
|
+
const len = lettersA.length;
|
|
1033
|
+
astrArr("alphabet", lettersA);
|
|
1034
|
+
const indexes = new Map(lettersA.map((l2, i2) => [l2, i2]));
|
|
1035
|
+
return {
|
|
1036
|
+
encode: (digits) => {
|
|
1037
|
+
aArr(digits);
|
|
1038
|
+
return digits.map((i2) => {
|
|
1039
|
+
if (!Number.isSafeInteger(i2) || i2 < 0 || i2 >= len)
|
|
1040
|
+
throw new Error(`alphabet.encode: digit index outside alphabet "${i2}". Allowed: ${letters}`);
|
|
1041
|
+
return lettersA[i2];
|
|
1042
|
+
});
|
|
1043
|
+
},
|
|
1044
|
+
decode: (input) => {
|
|
1045
|
+
aArr(input);
|
|
1046
|
+
return input.map((letter) => {
|
|
1047
|
+
astr("alphabet.decode", letter);
|
|
1048
|
+
const i2 = indexes.get(letter);
|
|
1049
|
+
if (i2 === void 0)
|
|
1050
|
+
throw new Error(`Unknown letter: "${letter}". Allowed: ${letters}`);
|
|
1051
|
+
return i2;
|
|
1052
|
+
});
|
|
1053
|
+
}
|
|
1054
|
+
};
|
|
1055
|
+
}
|
|
1056
|
+
// @__NO_SIDE_EFFECTS__
|
|
1057
|
+
function join2(separator = "") {
|
|
1058
|
+
astr("join", separator);
|
|
1059
|
+
return {
|
|
1060
|
+
encode: (from) => {
|
|
1061
|
+
astrArr("join.decode", from);
|
|
1062
|
+
return from.join(separator);
|
|
1063
|
+
},
|
|
1064
|
+
decode: (to) => {
|
|
1065
|
+
astr("join.decode", to);
|
|
1066
|
+
return to.split(separator);
|
|
1067
|
+
}
|
|
1068
|
+
};
|
|
1069
|
+
}
|
|
1070
|
+
// @__NO_SIDE_EFFECTS__
|
|
1071
|
+
function padding(bits, chr = "=") {
|
|
1072
|
+
anumber(bits);
|
|
1073
|
+
astr("padding", chr);
|
|
1074
|
+
return {
|
|
1075
|
+
encode(data) {
|
|
1076
|
+
astrArr("padding.encode", data);
|
|
1077
|
+
while (data.length * bits % 8)
|
|
1078
|
+
data.push(chr);
|
|
1079
|
+
return data;
|
|
1080
|
+
},
|
|
1081
|
+
decode(input) {
|
|
1082
|
+
astrArr("padding.decode", input);
|
|
1083
|
+
let end = input.length;
|
|
1084
|
+
if (end * bits % 8)
|
|
1085
|
+
throw new Error("padding: invalid, string should have whole number of bytes");
|
|
1086
|
+
for (; end > 0 && input[end - 1] === chr; end--) {
|
|
1087
|
+
const last = end - 1;
|
|
1088
|
+
const byte = last * bits;
|
|
1089
|
+
if (byte % 8 === 0)
|
|
1090
|
+
throw new Error("padding: invalid, string has too much padding");
|
|
1091
|
+
}
|
|
1092
|
+
return input.slice(0, end);
|
|
1093
|
+
}
|
|
1094
|
+
};
|
|
1095
|
+
}
|
|
1096
|
+
var gcd = (a2, b3) => b3 === 0 ? a2 : gcd(b3, a2 % b3);
|
|
1097
|
+
var radix2carry = /* @__NO_SIDE_EFFECTS__ */ (from, to) => from + (to - gcd(from, to));
|
|
1098
|
+
var powers = /* @__PURE__ */ (() => {
|
|
1099
|
+
let res = [];
|
|
1100
|
+
for (let i2 = 0; i2 < 40; i2++)
|
|
1101
|
+
res.push(2 ** i2);
|
|
1102
|
+
return res;
|
|
1103
|
+
})();
|
|
1104
|
+
function convertRadix2(data, from, to, padding2) {
|
|
1105
|
+
aArr(data);
|
|
1106
|
+
if (from <= 0 || from > 32)
|
|
1107
|
+
throw new RangeError(`convertRadix2: wrong from=${from}`);
|
|
1108
|
+
if (to <= 0 || to > 32)
|
|
1109
|
+
throw new RangeError(`convertRadix2: wrong to=${to}`);
|
|
1110
|
+
if (/* @__PURE__ */ radix2carry(from, to) > 32) {
|
|
1111
|
+
throw new Error(`convertRadix2: carry overflow from=${from} to=${to} carryBits=${/* @__PURE__ */ radix2carry(from, to)}`);
|
|
1112
|
+
}
|
|
1113
|
+
let carry = 0;
|
|
1114
|
+
let pos = 0;
|
|
1115
|
+
const max = powers[from];
|
|
1116
|
+
const mask = powers[to] - 1;
|
|
1117
|
+
const res = [];
|
|
1118
|
+
for (const n of data) {
|
|
1119
|
+
anumber(n);
|
|
1120
|
+
if (n >= max)
|
|
1121
|
+
throw new Error(`convertRadix2: invalid data word=${n} from=${from}`);
|
|
1122
|
+
carry = carry << from | n;
|
|
1123
|
+
if (pos + from > 32)
|
|
1124
|
+
throw new Error(`convertRadix2: carry overflow pos=${pos} from=${from}`);
|
|
1125
|
+
pos += from;
|
|
1126
|
+
for (; pos >= to; pos -= to)
|
|
1127
|
+
res.push((carry >> pos - to & mask) >>> 0);
|
|
1128
|
+
const pow = powers[pos];
|
|
1129
|
+
if (pow === void 0)
|
|
1130
|
+
throw new Error("invalid carry");
|
|
1131
|
+
carry &= pow - 1;
|
|
1132
|
+
}
|
|
1133
|
+
carry = carry << to - pos & mask;
|
|
1134
|
+
if (!padding2 && pos >= from)
|
|
1135
|
+
throw new Error("Excess padding");
|
|
1136
|
+
if (!padding2 && carry > 0)
|
|
1137
|
+
throw new Error(`Non-zero padding: ${carry}`);
|
|
1138
|
+
if (padding2 && pos > 0)
|
|
1139
|
+
res.push(carry >>> 0);
|
|
1140
|
+
return res;
|
|
1141
|
+
}
|
|
1142
|
+
// @__NO_SIDE_EFFECTS__
|
|
1143
|
+
function radix2(bits, revPadding = false) {
|
|
1144
|
+
anumber(bits);
|
|
1145
|
+
if (bits <= 0 || bits > 32)
|
|
1146
|
+
throw new RangeError("radix2: bits should be in (0..32]");
|
|
1147
|
+
if (/* @__PURE__ */ radix2carry(8, bits) > 32 || /* @__PURE__ */ radix2carry(bits, 8) > 32)
|
|
1148
|
+
throw new RangeError("radix2: carry overflow");
|
|
1149
|
+
return {
|
|
1150
|
+
encode: (bytes) => {
|
|
1151
|
+
if (!isBytes(bytes))
|
|
1152
|
+
throw new TypeError("radix2.encode input should be Uint8Array");
|
|
1153
|
+
return convertRadix2(Array.from(bytes), 8, bits, !revPadding);
|
|
1154
|
+
},
|
|
1155
|
+
decode: (digits) => {
|
|
1156
|
+
anumArr("radix2.decode", digits);
|
|
1157
|
+
return Uint8Array.from(convertRadix2(digits, bits, 8, revPadding));
|
|
1158
|
+
}
|
|
1159
|
+
};
|
|
1160
|
+
}
|
|
1161
|
+
var base32 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ chain(/* @__PURE__ */ radix2(5), /* @__PURE__ */ alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"), /* @__PURE__ */ padding(5), /* @__PURE__ */ join2("")));
|
|
1162
|
+
|
|
1163
|
+
// ../../node_modules/.pnpm/@otplib+plugin-base32-scure@13.4.0/node_modules/@otplib/plugin-base32-scure/dist/index.js
|
|
1164
|
+
var r = class {
|
|
1165
|
+
name = "scure";
|
|
1166
|
+
encode(o, e = {}) {
|
|
1167
|
+
let { padding: t2 = false } = e, n = base32.encode(o);
|
|
1168
|
+
return t2 ? n : n.replace(/=+$/, "");
|
|
1169
|
+
}
|
|
1170
|
+
decode(o) {
|
|
1171
|
+
try {
|
|
1172
|
+
let e = o.toUpperCase(), t2 = e.padEnd(Math.ceil(e.length / 8) * 8, "=");
|
|
1173
|
+
return base32.decode(t2);
|
|
1174
|
+
} catch (e) {
|
|
1175
|
+
throw e instanceof Error ? new Error(`Invalid Base32 string: ${e.message}`) : new Error("Invalid Base32 string");
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
};
|
|
1179
|
+
var d2 = Object.freeze(new r());
|
|
1180
|
+
|
|
1181
|
+
// ../../node_modules/.pnpm/@noble+hashes@2.2.0/node_modules/@noble/hashes/utils.js
|
|
1182
|
+
function isBytes2(a2) {
|
|
1183
|
+
return a2 instanceof Uint8Array || ArrayBuffer.isView(a2) && a2.constructor.name === "Uint8Array" && "BYTES_PER_ELEMENT" in a2 && a2.BYTES_PER_ELEMENT === 1;
|
|
1184
|
+
}
|
|
1185
|
+
function anumber2(n, title = "") {
|
|
1186
|
+
if (typeof n !== "number") {
|
|
1187
|
+
const prefix = title && `"${title}" `;
|
|
1188
|
+
throw new TypeError(`${prefix}expected number, got ${typeof n}`);
|
|
1189
|
+
}
|
|
1190
|
+
if (!Number.isSafeInteger(n) || n < 0) {
|
|
1191
|
+
const prefix = title && `"${title}" `;
|
|
1192
|
+
throw new RangeError(`${prefix}expected integer >= 0, got ${n}`);
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
function abytes(value, length, title = "") {
|
|
1196
|
+
const bytes = isBytes2(value);
|
|
1197
|
+
const len = value?.length;
|
|
1198
|
+
const needsLen = length !== void 0;
|
|
1199
|
+
if (!bytes || needsLen && len !== length) {
|
|
1200
|
+
const prefix = title && `"${title}" `;
|
|
1201
|
+
const ofLen = needsLen ? ` of length ${length}` : "";
|
|
1202
|
+
const got = bytes ? `length=${len}` : `type=${typeof value}`;
|
|
1203
|
+
const message = prefix + "expected Uint8Array" + ofLen + ", got " + got;
|
|
1204
|
+
if (!bytes)
|
|
1205
|
+
throw new TypeError(message);
|
|
1206
|
+
throw new RangeError(message);
|
|
1207
|
+
}
|
|
1208
|
+
return value;
|
|
1209
|
+
}
|
|
1210
|
+
function ahash(h3) {
|
|
1211
|
+
if (typeof h3 !== "function" || typeof h3.create !== "function")
|
|
1212
|
+
throw new TypeError("Hash must wrapped by utils.createHasher");
|
|
1213
|
+
anumber2(h3.outputLen);
|
|
1214
|
+
anumber2(h3.blockLen);
|
|
1215
|
+
if (h3.outputLen < 1)
|
|
1216
|
+
throw new Error('"outputLen" must be >= 1');
|
|
1217
|
+
if (h3.blockLen < 1)
|
|
1218
|
+
throw new Error('"blockLen" must be >= 1');
|
|
1219
|
+
}
|
|
1220
|
+
function aexists(instance, checkFinished = true) {
|
|
1221
|
+
if (instance.destroyed)
|
|
1222
|
+
throw new Error("Hash instance has been destroyed");
|
|
1223
|
+
if (checkFinished && instance.finished)
|
|
1224
|
+
throw new Error("Hash#digest() has already been called");
|
|
1225
|
+
}
|
|
1226
|
+
function aoutput(out, instance) {
|
|
1227
|
+
abytes(out, void 0, "digestInto() output");
|
|
1228
|
+
const min = instance.outputLen;
|
|
1229
|
+
if (out.length < min) {
|
|
1230
|
+
throw new RangeError('"digestInto() output" expected to be of length >=' + min);
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
function clean(...arrays) {
|
|
1234
|
+
for (let i2 = 0; i2 < arrays.length; i2++) {
|
|
1235
|
+
arrays[i2].fill(0);
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
function createView(arr) {
|
|
1239
|
+
return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
|
|
1240
|
+
}
|
|
1241
|
+
function rotr(word, shift) {
|
|
1242
|
+
return word << 32 - shift | word >>> shift;
|
|
1243
|
+
}
|
|
1244
|
+
function rotl(word, shift) {
|
|
1245
|
+
return word << shift | word >>> 32 - shift >>> 0;
|
|
1246
|
+
}
|
|
1247
|
+
function createHasher(hashCons, info = {}) {
|
|
1248
|
+
const hashC = (msg, opts) => hashCons(opts).update(msg).digest();
|
|
1249
|
+
const tmp = hashCons(void 0);
|
|
1250
|
+
hashC.outputLen = tmp.outputLen;
|
|
1251
|
+
hashC.blockLen = tmp.blockLen;
|
|
1252
|
+
hashC.canXOF = tmp.canXOF;
|
|
1253
|
+
hashC.create = (opts) => hashCons(opts);
|
|
1254
|
+
Object.assign(hashC, info);
|
|
1255
|
+
return Object.freeze(hashC);
|
|
1256
|
+
}
|
|
1257
|
+
function randomBytes(bytesLength = 32) {
|
|
1258
|
+
anumber2(bytesLength, "bytesLength");
|
|
1259
|
+
const cr2 = typeof globalThis === "object" ? globalThis.crypto : null;
|
|
1260
|
+
if (typeof cr2?.getRandomValues !== "function")
|
|
1261
|
+
throw new Error("crypto.getRandomValues must be defined");
|
|
1262
|
+
if (bytesLength > 65536)
|
|
1263
|
+
throw new RangeError(`"bytesLength" expected <= 65536, got ${bytesLength}`);
|
|
1264
|
+
return cr2.getRandomValues(new Uint8Array(bytesLength));
|
|
1265
|
+
}
|
|
1266
|
+
var oidNist = (suffix) => ({
|
|
1267
|
+
// Current NIST hashAlgs suffixes used here fit in one DER subidentifier octet.
|
|
1268
|
+
// Larger suffix values would need base-128 OID encoding and a different length byte.
|
|
1269
|
+
oid: Uint8Array.from([6, 9, 96, 134, 72, 1, 101, 3, 4, 2, suffix])
|
|
1270
|
+
});
|
|
1271
|
+
|
|
1272
|
+
// ../../node_modules/.pnpm/@noble+hashes@2.2.0/node_modules/@noble/hashes/hmac.js
|
|
1273
|
+
var _HMAC = class {
|
|
1274
|
+
oHash;
|
|
1275
|
+
iHash;
|
|
1276
|
+
blockLen;
|
|
1277
|
+
outputLen;
|
|
1278
|
+
canXOF = false;
|
|
1279
|
+
finished = false;
|
|
1280
|
+
destroyed = false;
|
|
1281
|
+
constructor(hash, key) {
|
|
1282
|
+
ahash(hash);
|
|
1283
|
+
abytes(key, void 0, "key");
|
|
1284
|
+
this.iHash = hash.create();
|
|
1285
|
+
if (typeof this.iHash.update !== "function")
|
|
1286
|
+
throw new Error("Expected instance of class which extends utils.Hash");
|
|
1287
|
+
this.blockLen = this.iHash.blockLen;
|
|
1288
|
+
this.outputLen = this.iHash.outputLen;
|
|
1289
|
+
const blockLen = this.blockLen;
|
|
1290
|
+
const pad = new Uint8Array(blockLen);
|
|
1291
|
+
pad.set(key.length > blockLen ? hash.create().update(key).digest() : key);
|
|
1292
|
+
for (let i2 = 0; i2 < pad.length; i2++)
|
|
1293
|
+
pad[i2] ^= 54;
|
|
1294
|
+
this.iHash.update(pad);
|
|
1295
|
+
this.oHash = hash.create();
|
|
1296
|
+
for (let i2 = 0; i2 < pad.length; i2++)
|
|
1297
|
+
pad[i2] ^= 54 ^ 92;
|
|
1298
|
+
this.oHash.update(pad);
|
|
1299
|
+
clean(pad);
|
|
1300
|
+
}
|
|
1301
|
+
update(buf) {
|
|
1302
|
+
aexists(this);
|
|
1303
|
+
this.iHash.update(buf);
|
|
1304
|
+
return this;
|
|
1305
|
+
}
|
|
1306
|
+
digestInto(out) {
|
|
1307
|
+
aexists(this);
|
|
1308
|
+
aoutput(out, this);
|
|
1309
|
+
this.finished = true;
|
|
1310
|
+
const buf = out.subarray(0, this.outputLen);
|
|
1311
|
+
this.iHash.digestInto(buf);
|
|
1312
|
+
this.oHash.update(buf);
|
|
1313
|
+
this.oHash.digestInto(buf);
|
|
1314
|
+
this.destroy();
|
|
1315
|
+
}
|
|
1316
|
+
digest() {
|
|
1317
|
+
const out = new Uint8Array(this.oHash.outputLen);
|
|
1318
|
+
this.digestInto(out);
|
|
1319
|
+
return out;
|
|
1320
|
+
}
|
|
1321
|
+
_cloneInto(to) {
|
|
1322
|
+
to ||= Object.create(Object.getPrototypeOf(this), {});
|
|
1323
|
+
const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this;
|
|
1324
|
+
to = to;
|
|
1325
|
+
to.finished = finished;
|
|
1326
|
+
to.destroyed = destroyed;
|
|
1327
|
+
to.blockLen = blockLen;
|
|
1328
|
+
to.outputLen = outputLen;
|
|
1329
|
+
to.oHash = oHash._cloneInto(to.oHash);
|
|
1330
|
+
to.iHash = iHash._cloneInto(to.iHash);
|
|
1331
|
+
return to;
|
|
1332
|
+
}
|
|
1333
|
+
clone() {
|
|
1334
|
+
return this._cloneInto();
|
|
1335
|
+
}
|
|
1336
|
+
destroy() {
|
|
1337
|
+
this.destroyed = true;
|
|
1338
|
+
this.oHash.destroy();
|
|
1339
|
+
this.iHash.destroy();
|
|
1340
|
+
}
|
|
1341
|
+
};
|
|
1342
|
+
var hmac = /* @__PURE__ */ (() => {
|
|
1343
|
+
const hmac_ = ((hash, key, message) => new _HMAC(hash, key).update(message).digest());
|
|
1344
|
+
hmac_.create = (hash, key) => new _HMAC(hash, key);
|
|
1345
|
+
return hmac_;
|
|
1346
|
+
})();
|
|
1347
|
+
|
|
1348
|
+
// ../../node_modules/.pnpm/@noble+hashes@2.2.0/node_modules/@noble/hashes/_md.js
|
|
1349
|
+
function Chi(a2, b3, c3) {
|
|
1350
|
+
return a2 & b3 ^ ~a2 & c3;
|
|
1351
|
+
}
|
|
1352
|
+
function Maj(a2, b3, c3) {
|
|
1353
|
+
return a2 & b3 ^ a2 & c3 ^ b3 & c3;
|
|
1354
|
+
}
|
|
1355
|
+
var HashMD = class {
|
|
1356
|
+
blockLen;
|
|
1357
|
+
outputLen;
|
|
1358
|
+
canXOF = false;
|
|
1359
|
+
padOffset;
|
|
1360
|
+
isLE;
|
|
1361
|
+
// For partial updates less than block size
|
|
1362
|
+
buffer;
|
|
1363
|
+
view;
|
|
1364
|
+
finished = false;
|
|
1365
|
+
length = 0;
|
|
1366
|
+
pos = 0;
|
|
1367
|
+
destroyed = false;
|
|
1368
|
+
constructor(blockLen, outputLen, padOffset, isLE) {
|
|
1369
|
+
this.blockLen = blockLen;
|
|
1370
|
+
this.outputLen = outputLen;
|
|
1371
|
+
this.padOffset = padOffset;
|
|
1372
|
+
this.isLE = isLE;
|
|
1373
|
+
this.buffer = new Uint8Array(blockLen);
|
|
1374
|
+
this.view = createView(this.buffer);
|
|
1375
|
+
}
|
|
1376
|
+
update(data) {
|
|
1377
|
+
aexists(this);
|
|
1378
|
+
abytes(data);
|
|
1379
|
+
const { view, buffer, blockLen } = this;
|
|
1380
|
+
const len = data.length;
|
|
1381
|
+
for (let pos = 0; pos < len; ) {
|
|
1382
|
+
const take = Math.min(blockLen - this.pos, len - pos);
|
|
1383
|
+
if (take === blockLen) {
|
|
1384
|
+
const dataView = createView(data);
|
|
1385
|
+
for (; blockLen <= len - pos; pos += blockLen)
|
|
1386
|
+
this.process(dataView, pos);
|
|
1387
|
+
continue;
|
|
1388
|
+
}
|
|
1389
|
+
buffer.set(data.subarray(pos, pos + take), this.pos);
|
|
1390
|
+
this.pos += take;
|
|
1391
|
+
pos += take;
|
|
1392
|
+
if (this.pos === blockLen) {
|
|
1393
|
+
this.process(view, 0);
|
|
1394
|
+
this.pos = 0;
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
this.length += data.length;
|
|
1398
|
+
this.roundClean();
|
|
1399
|
+
return this;
|
|
1400
|
+
}
|
|
1401
|
+
digestInto(out) {
|
|
1402
|
+
aexists(this);
|
|
1403
|
+
aoutput(out, this);
|
|
1404
|
+
this.finished = true;
|
|
1405
|
+
const { buffer, view, blockLen, isLE } = this;
|
|
1406
|
+
let { pos } = this;
|
|
1407
|
+
buffer[pos++] = 128;
|
|
1408
|
+
clean(this.buffer.subarray(pos));
|
|
1409
|
+
if (this.padOffset > blockLen - pos) {
|
|
1410
|
+
this.process(view, 0);
|
|
1411
|
+
pos = 0;
|
|
1412
|
+
}
|
|
1413
|
+
for (let i2 = pos; i2 < blockLen; i2++)
|
|
1414
|
+
buffer[i2] = 0;
|
|
1415
|
+
view.setBigUint64(blockLen - 8, BigInt(this.length * 8), isLE);
|
|
1416
|
+
this.process(view, 0);
|
|
1417
|
+
const oview = createView(out);
|
|
1418
|
+
const len = this.outputLen;
|
|
1419
|
+
if (len % 4)
|
|
1420
|
+
throw new Error("_sha2: outputLen must be aligned to 32bit");
|
|
1421
|
+
const outLen = len / 4;
|
|
1422
|
+
const state = this.get();
|
|
1423
|
+
if (outLen > state.length)
|
|
1424
|
+
throw new Error("_sha2: outputLen bigger than state");
|
|
1425
|
+
for (let i2 = 0; i2 < outLen; i2++)
|
|
1426
|
+
oview.setUint32(4 * i2, state[i2], isLE);
|
|
1427
|
+
}
|
|
1428
|
+
digest() {
|
|
1429
|
+
const { buffer, outputLen } = this;
|
|
1430
|
+
this.digestInto(buffer);
|
|
1431
|
+
const res = buffer.slice(0, outputLen);
|
|
1432
|
+
this.destroy();
|
|
1433
|
+
return res;
|
|
1434
|
+
}
|
|
1435
|
+
_cloneInto(to) {
|
|
1436
|
+
to ||= new this.constructor();
|
|
1437
|
+
to.set(...this.get());
|
|
1438
|
+
const { blockLen, buffer, length, finished, destroyed, pos } = this;
|
|
1439
|
+
to.destroyed = destroyed;
|
|
1440
|
+
to.finished = finished;
|
|
1441
|
+
to.length = length;
|
|
1442
|
+
to.pos = pos;
|
|
1443
|
+
if (length % blockLen)
|
|
1444
|
+
to.buffer.set(buffer);
|
|
1445
|
+
return to;
|
|
1446
|
+
}
|
|
1447
|
+
clone() {
|
|
1448
|
+
return this._cloneInto();
|
|
1449
|
+
}
|
|
1450
|
+
};
|
|
1451
|
+
var SHA256_IV = /* @__PURE__ */ Uint32Array.from([
|
|
1452
|
+
1779033703,
|
|
1453
|
+
3144134277,
|
|
1454
|
+
1013904242,
|
|
1455
|
+
2773480762,
|
|
1456
|
+
1359893119,
|
|
1457
|
+
2600822924,
|
|
1458
|
+
528734635,
|
|
1459
|
+
1541459225
|
|
1460
|
+
]);
|
|
1461
|
+
var SHA512_IV = /* @__PURE__ */ Uint32Array.from([
|
|
1462
|
+
1779033703,
|
|
1463
|
+
4089235720,
|
|
1464
|
+
3144134277,
|
|
1465
|
+
2227873595,
|
|
1466
|
+
1013904242,
|
|
1467
|
+
4271175723,
|
|
1468
|
+
2773480762,
|
|
1469
|
+
1595750129,
|
|
1470
|
+
1359893119,
|
|
1471
|
+
2917565137,
|
|
1472
|
+
2600822924,
|
|
1473
|
+
725511199,
|
|
1474
|
+
528734635,
|
|
1475
|
+
4215389547,
|
|
1476
|
+
1541459225,
|
|
1477
|
+
327033209
|
|
1478
|
+
]);
|
|
1479
|
+
|
|
1480
|
+
// ../../node_modules/.pnpm/@noble+hashes@2.2.0/node_modules/@noble/hashes/legacy.js
|
|
1481
|
+
var SHA1_IV = /* @__PURE__ */ Uint32Array.from([
|
|
1482
|
+
1732584193,
|
|
1483
|
+
4023233417,
|
|
1484
|
+
2562383102,
|
|
1485
|
+
271733878,
|
|
1486
|
+
3285377520
|
|
1487
|
+
]);
|
|
1488
|
+
var SHA1_W = /* @__PURE__ */ new Uint32Array(80);
|
|
1489
|
+
var _SHA1 = class extends HashMD {
|
|
1490
|
+
A = SHA1_IV[0] | 0;
|
|
1491
|
+
B = SHA1_IV[1] | 0;
|
|
1492
|
+
C = SHA1_IV[2] | 0;
|
|
1493
|
+
D = SHA1_IV[3] | 0;
|
|
1494
|
+
E = SHA1_IV[4] | 0;
|
|
1495
|
+
constructor() {
|
|
1496
|
+
super(64, 20, 8, false);
|
|
1497
|
+
}
|
|
1498
|
+
get() {
|
|
1499
|
+
const { A: A3, B: B2, C: C2, D, E: E2 } = this;
|
|
1500
|
+
return [A3, B2, C2, D, E2];
|
|
1501
|
+
}
|
|
1502
|
+
set(A3, B2, C2, D, E2) {
|
|
1503
|
+
this.A = A3 | 0;
|
|
1504
|
+
this.B = B2 | 0;
|
|
1505
|
+
this.C = C2 | 0;
|
|
1506
|
+
this.D = D | 0;
|
|
1507
|
+
this.E = E2 | 0;
|
|
1508
|
+
}
|
|
1509
|
+
process(view, offset) {
|
|
1510
|
+
for (let i2 = 0; i2 < 16; i2++, offset += 4)
|
|
1511
|
+
SHA1_W[i2] = view.getUint32(offset, false);
|
|
1512
|
+
for (let i2 = 16; i2 < 80; i2++)
|
|
1513
|
+
SHA1_W[i2] = rotl(SHA1_W[i2 - 3] ^ SHA1_W[i2 - 8] ^ SHA1_W[i2 - 14] ^ SHA1_W[i2 - 16], 1);
|
|
1514
|
+
let { A: A3, B: B2, C: C2, D, E: E2 } = this;
|
|
1515
|
+
for (let i2 = 0; i2 < 80; i2++) {
|
|
1516
|
+
let F2, K2;
|
|
1517
|
+
if (i2 < 20) {
|
|
1518
|
+
F2 = Chi(B2, C2, D);
|
|
1519
|
+
K2 = 1518500249;
|
|
1520
|
+
} else if (i2 < 40) {
|
|
1521
|
+
F2 = B2 ^ C2 ^ D;
|
|
1522
|
+
K2 = 1859775393;
|
|
1523
|
+
} else if (i2 < 60) {
|
|
1524
|
+
F2 = Maj(B2, C2, D);
|
|
1525
|
+
K2 = 2400959708;
|
|
1526
|
+
} else {
|
|
1527
|
+
F2 = B2 ^ C2 ^ D;
|
|
1528
|
+
K2 = 3395469782;
|
|
1529
|
+
}
|
|
1530
|
+
const T3 = rotl(A3, 5) + F2 + E2 + K2 + SHA1_W[i2] | 0;
|
|
1531
|
+
E2 = D;
|
|
1532
|
+
D = C2;
|
|
1533
|
+
C2 = rotl(B2, 30);
|
|
1534
|
+
B2 = A3;
|
|
1535
|
+
A3 = T3;
|
|
1536
|
+
}
|
|
1537
|
+
A3 = A3 + this.A | 0;
|
|
1538
|
+
B2 = B2 + this.B | 0;
|
|
1539
|
+
C2 = C2 + this.C | 0;
|
|
1540
|
+
D = D + this.D | 0;
|
|
1541
|
+
E2 = E2 + this.E | 0;
|
|
1542
|
+
this.set(A3, B2, C2, D, E2);
|
|
1543
|
+
}
|
|
1544
|
+
roundClean() {
|
|
1545
|
+
clean(SHA1_W);
|
|
1546
|
+
}
|
|
1547
|
+
destroy() {
|
|
1548
|
+
this.destroyed = true;
|
|
1549
|
+
this.set(0, 0, 0, 0, 0);
|
|
1550
|
+
clean(this.buffer);
|
|
1551
|
+
}
|
|
1552
|
+
};
|
|
1553
|
+
var sha1 = /* @__PURE__ */ createHasher(() => new _SHA1());
|
|
1554
|
+
|
|
1555
|
+
// ../../node_modules/.pnpm/@noble+hashes@2.2.0/node_modules/@noble/hashes/_u64.js
|
|
1556
|
+
var U32_MASK64 = /* @__PURE__ */ BigInt(2 ** 32 - 1);
|
|
1557
|
+
var _32n = /* @__PURE__ */ BigInt(32);
|
|
1558
|
+
function fromBig(n, le = false) {
|
|
1559
|
+
if (le)
|
|
1560
|
+
return { h: Number(n & U32_MASK64), l: Number(n >> _32n & U32_MASK64) };
|
|
1561
|
+
return { h: Number(n >> _32n & U32_MASK64) | 0, l: Number(n & U32_MASK64) | 0 };
|
|
1562
|
+
}
|
|
1563
|
+
function split(lst, le = false) {
|
|
1564
|
+
const len = lst.length;
|
|
1565
|
+
let Ah = new Uint32Array(len);
|
|
1566
|
+
let Al = new Uint32Array(len);
|
|
1567
|
+
for (let i2 = 0; i2 < len; i2++) {
|
|
1568
|
+
const { h: h3, l: l2 } = fromBig(lst[i2], le);
|
|
1569
|
+
[Ah[i2], Al[i2]] = [h3, l2];
|
|
1570
|
+
}
|
|
1571
|
+
return [Ah, Al];
|
|
1572
|
+
}
|
|
1573
|
+
var shrSH = (h3, _l, s) => h3 >>> s;
|
|
1574
|
+
var shrSL = (h3, l2, s) => h3 << 32 - s | l2 >>> s;
|
|
1575
|
+
var rotrSH = (h3, l2, s) => h3 >>> s | l2 << 32 - s;
|
|
1576
|
+
var rotrSL = (h3, l2, s) => h3 << 32 - s | l2 >>> s;
|
|
1577
|
+
var rotrBH = (h3, l2, s) => h3 << 64 - s | l2 >>> s - 32;
|
|
1578
|
+
var rotrBL = (h3, l2, s) => h3 >>> s - 32 | l2 << 64 - s;
|
|
1579
|
+
function add(Ah, Al, Bh, Bl) {
|
|
1580
|
+
const l2 = (Al >>> 0) + (Bl >>> 0);
|
|
1581
|
+
return { h: Ah + Bh + (l2 / 2 ** 32 | 0) | 0, l: l2 | 0 };
|
|
1582
|
+
}
|
|
1583
|
+
var add3L = (Al, Bl, Cl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0);
|
|
1584
|
+
var add3H = (low, Ah, Bh, Ch) => Ah + Bh + Ch + (low / 2 ** 32 | 0) | 0;
|
|
1585
|
+
var add4L = (Al, Bl, Cl, Dl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0);
|
|
1586
|
+
var add4H = (low, Ah, Bh, Ch, Dh) => Ah + Bh + Ch + Dh + (low / 2 ** 32 | 0) | 0;
|
|
1587
|
+
var add5L = (Al, Bl, Cl, Dl, El) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0) + (El >>> 0);
|
|
1588
|
+
var add5H = (low, Ah, Bh, Ch, Dh, Eh) => Ah + Bh + Ch + Dh + Eh + (low / 2 ** 32 | 0) | 0;
|
|
1589
|
+
|
|
1590
|
+
// ../../node_modules/.pnpm/@noble+hashes@2.2.0/node_modules/@noble/hashes/sha2.js
|
|
1591
|
+
var SHA256_K = /* @__PURE__ */ Uint32Array.from([
|
|
1592
|
+
1116352408,
|
|
1593
|
+
1899447441,
|
|
1594
|
+
3049323471,
|
|
1595
|
+
3921009573,
|
|
1596
|
+
961987163,
|
|
1597
|
+
1508970993,
|
|
1598
|
+
2453635748,
|
|
1599
|
+
2870763221,
|
|
1600
|
+
3624381080,
|
|
1601
|
+
310598401,
|
|
1602
|
+
607225278,
|
|
1603
|
+
1426881987,
|
|
1604
|
+
1925078388,
|
|
1605
|
+
2162078206,
|
|
1606
|
+
2614888103,
|
|
1607
|
+
3248222580,
|
|
1608
|
+
3835390401,
|
|
1609
|
+
4022224774,
|
|
1610
|
+
264347078,
|
|
1611
|
+
604807628,
|
|
1612
|
+
770255983,
|
|
1613
|
+
1249150122,
|
|
1614
|
+
1555081692,
|
|
1615
|
+
1996064986,
|
|
1616
|
+
2554220882,
|
|
1617
|
+
2821834349,
|
|
1618
|
+
2952996808,
|
|
1619
|
+
3210313671,
|
|
1620
|
+
3336571891,
|
|
1621
|
+
3584528711,
|
|
1622
|
+
113926993,
|
|
1623
|
+
338241895,
|
|
1624
|
+
666307205,
|
|
1625
|
+
773529912,
|
|
1626
|
+
1294757372,
|
|
1627
|
+
1396182291,
|
|
1628
|
+
1695183700,
|
|
1629
|
+
1986661051,
|
|
1630
|
+
2177026350,
|
|
1631
|
+
2456956037,
|
|
1632
|
+
2730485921,
|
|
1633
|
+
2820302411,
|
|
1634
|
+
3259730800,
|
|
1635
|
+
3345764771,
|
|
1636
|
+
3516065817,
|
|
1637
|
+
3600352804,
|
|
1638
|
+
4094571909,
|
|
1639
|
+
275423344,
|
|
1640
|
+
430227734,
|
|
1641
|
+
506948616,
|
|
1642
|
+
659060556,
|
|
1643
|
+
883997877,
|
|
1644
|
+
958139571,
|
|
1645
|
+
1322822218,
|
|
1646
|
+
1537002063,
|
|
1647
|
+
1747873779,
|
|
1648
|
+
1955562222,
|
|
1649
|
+
2024104815,
|
|
1650
|
+
2227730452,
|
|
1651
|
+
2361852424,
|
|
1652
|
+
2428436474,
|
|
1653
|
+
2756734187,
|
|
1654
|
+
3204031479,
|
|
1655
|
+
3329325298
|
|
1656
|
+
]);
|
|
1657
|
+
var SHA256_W = /* @__PURE__ */ new Uint32Array(64);
|
|
1658
|
+
var SHA2_32B = class extends HashMD {
|
|
1659
|
+
constructor(outputLen) {
|
|
1660
|
+
super(64, outputLen, 8, false);
|
|
1661
|
+
}
|
|
1662
|
+
get() {
|
|
1663
|
+
const { A: A3, B: B2, C: C2, D, E: E2, F: F2, G: G3, H } = this;
|
|
1664
|
+
return [A3, B2, C2, D, E2, F2, G3, H];
|
|
1665
|
+
}
|
|
1666
|
+
// prettier-ignore
|
|
1667
|
+
set(A3, B2, C2, D, E2, F2, G3, H) {
|
|
1668
|
+
this.A = A3 | 0;
|
|
1669
|
+
this.B = B2 | 0;
|
|
1670
|
+
this.C = C2 | 0;
|
|
1671
|
+
this.D = D | 0;
|
|
1672
|
+
this.E = E2 | 0;
|
|
1673
|
+
this.F = F2 | 0;
|
|
1674
|
+
this.G = G3 | 0;
|
|
1675
|
+
this.H = H | 0;
|
|
1676
|
+
}
|
|
1677
|
+
process(view, offset) {
|
|
1678
|
+
for (let i2 = 0; i2 < 16; i2++, offset += 4)
|
|
1679
|
+
SHA256_W[i2] = view.getUint32(offset, false);
|
|
1680
|
+
for (let i2 = 16; i2 < 64; i2++) {
|
|
1681
|
+
const W15 = SHA256_W[i2 - 15];
|
|
1682
|
+
const W2 = SHA256_W[i2 - 2];
|
|
1683
|
+
const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ W15 >>> 3;
|
|
1684
|
+
const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ W2 >>> 10;
|
|
1685
|
+
SHA256_W[i2] = s1 + SHA256_W[i2 - 7] + s0 + SHA256_W[i2 - 16] | 0;
|
|
1686
|
+
}
|
|
1687
|
+
let { A: A3, B: B2, C: C2, D, E: E2, F: F2, G: G3, H } = this;
|
|
1688
|
+
for (let i2 = 0; i2 < 64; i2++) {
|
|
1689
|
+
const sigma1 = rotr(E2, 6) ^ rotr(E2, 11) ^ rotr(E2, 25);
|
|
1690
|
+
const T1 = H + sigma1 + Chi(E2, F2, G3) + SHA256_K[i2] + SHA256_W[i2] | 0;
|
|
1691
|
+
const sigma0 = rotr(A3, 2) ^ rotr(A3, 13) ^ rotr(A3, 22);
|
|
1692
|
+
const T22 = sigma0 + Maj(A3, B2, C2) | 0;
|
|
1693
|
+
H = G3;
|
|
1694
|
+
G3 = F2;
|
|
1695
|
+
F2 = E2;
|
|
1696
|
+
E2 = D + T1 | 0;
|
|
1697
|
+
D = C2;
|
|
1698
|
+
C2 = B2;
|
|
1699
|
+
B2 = A3;
|
|
1700
|
+
A3 = T1 + T22 | 0;
|
|
1701
|
+
}
|
|
1702
|
+
A3 = A3 + this.A | 0;
|
|
1703
|
+
B2 = B2 + this.B | 0;
|
|
1704
|
+
C2 = C2 + this.C | 0;
|
|
1705
|
+
D = D + this.D | 0;
|
|
1706
|
+
E2 = E2 + this.E | 0;
|
|
1707
|
+
F2 = F2 + this.F | 0;
|
|
1708
|
+
G3 = G3 + this.G | 0;
|
|
1709
|
+
H = H + this.H | 0;
|
|
1710
|
+
this.set(A3, B2, C2, D, E2, F2, G3, H);
|
|
1711
|
+
}
|
|
1712
|
+
roundClean() {
|
|
1713
|
+
clean(SHA256_W);
|
|
1714
|
+
}
|
|
1715
|
+
destroy() {
|
|
1716
|
+
this.destroyed = true;
|
|
1717
|
+
this.set(0, 0, 0, 0, 0, 0, 0, 0);
|
|
1718
|
+
clean(this.buffer);
|
|
1719
|
+
}
|
|
1720
|
+
};
|
|
1721
|
+
var _SHA256 = class extends SHA2_32B {
|
|
1722
|
+
// We cannot use array here since array allows indexing by variable
|
|
1723
|
+
// which means optimizer/compiler cannot use registers.
|
|
1724
|
+
A = SHA256_IV[0] | 0;
|
|
1725
|
+
B = SHA256_IV[1] | 0;
|
|
1726
|
+
C = SHA256_IV[2] | 0;
|
|
1727
|
+
D = SHA256_IV[3] | 0;
|
|
1728
|
+
E = SHA256_IV[4] | 0;
|
|
1729
|
+
F = SHA256_IV[5] | 0;
|
|
1730
|
+
G = SHA256_IV[6] | 0;
|
|
1731
|
+
H = SHA256_IV[7] | 0;
|
|
1732
|
+
constructor() {
|
|
1733
|
+
super(32);
|
|
1734
|
+
}
|
|
1735
|
+
};
|
|
1736
|
+
var K512 = /* @__PURE__ */ (() => split([
|
|
1737
|
+
"0x428a2f98d728ae22",
|
|
1738
|
+
"0x7137449123ef65cd",
|
|
1739
|
+
"0xb5c0fbcfec4d3b2f",
|
|
1740
|
+
"0xe9b5dba58189dbbc",
|
|
1741
|
+
"0x3956c25bf348b538",
|
|
1742
|
+
"0x59f111f1b605d019",
|
|
1743
|
+
"0x923f82a4af194f9b",
|
|
1744
|
+
"0xab1c5ed5da6d8118",
|
|
1745
|
+
"0xd807aa98a3030242",
|
|
1746
|
+
"0x12835b0145706fbe",
|
|
1747
|
+
"0x243185be4ee4b28c",
|
|
1748
|
+
"0x550c7dc3d5ffb4e2",
|
|
1749
|
+
"0x72be5d74f27b896f",
|
|
1750
|
+
"0x80deb1fe3b1696b1",
|
|
1751
|
+
"0x9bdc06a725c71235",
|
|
1752
|
+
"0xc19bf174cf692694",
|
|
1753
|
+
"0xe49b69c19ef14ad2",
|
|
1754
|
+
"0xefbe4786384f25e3",
|
|
1755
|
+
"0x0fc19dc68b8cd5b5",
|
|
1756
|
+
"0x240ca1cc77ac9c65",
|
|
1757
|
+
"0x2de92c6f592b0275",
|
|
1758
|
+
"0x4a7484aa6ea6e483",
|
|
1759
|
+
"0x5cb0a9dcbd41fbd4",
|
|
1760
|
+
"0x76f988da831153b5",
|
|
1761
|
+
"0x983e5152ee66dfab",
|
|
1762
|
+
"0xa831c66d2db43210",
|
|
1763
|
+
"0xb00327c898fb213f",
|
|
1764
|
+
"0xbf597fc7beef0ee4",
|
|
1765
|
+
"0xc6e00bf33da88fc2",
|
|
1766
|
+
"0xd5a79147930aa725",
|
|
1767
|
+
"0x06ca6351e003826f",
|
|
1768
|
+
"0x142929670a0e6e70",
|
|
1769
|
+
"0x27b70a8546d22ffc",
|
|
1770
|
+
"0x2e1b21385c26c926",
|
|
1771
|
+
"0x4d2c6dfc5ac42aed",
|
|
1772
|
+
"0x53380d139d95b3df",
|
|
1773
|
+
"0x650a73548baf63de",
|
|
1774
|
+
"0x766a0abb3c77b2a8",
|
|
1775
|
+
"0x81c2c92e47edaee6",
|
|
1776
|
+
"0x92722c851482353b",
|
|
1777
|
+
"0xa2bfe8a14cf10364",
|
|
1778
|
+
"0xa81a664bbc423001",
|
|
1779
|
+
"0xc24b8b70d0f89791",
|
|
1780
|
+
"0xc76c51a30654be30",
|
|
1781
|
+
"0xd192e819d6ef5218",
|
|
1782
|
+
"0xd69906245565a910",
|
|
1783
|
+
"0xf40e35855771202a",
|
|
1784
|
+
"0x106aa07032bbd1b8",
|
|
1785
|
+
"0x19a4c116b8d2d0c8",
|
|
1786
|
+
"0x1e376c085141ab53",
|
|
1787
|
+
"0x2748774cdf8eeb99",
|
|
1788
|
+
"0x34b0bcb5e19b48a8",
|
|
1789
|
+
"0x391c0cb3c5c95a63",
|
|
1790
|
+
"0x4ed8aa4ae3418acb",
|
|
1791
|
+
"0x5b9cca4f7763e373",
|
|
1792
|
+
"0x682e6ff3d6b2b8a3",
|
|
1793
|
+
"0x748f82ee5defb2fc",
|
|
1794
|
+
"0x78a5636f43172f60",
|
|
1795
|
+
"0x84c87814a1f0ab72",
|
|
1796
|
+
"0x8cc702081a6439ec",
|
|
1797
|
+
"0x90befffa23631e28",
|
|
1798
|
+
"0xa4506cebde82bde9",
|
|
1799
|
+
"0xbef9a3f7b2c67915",
|
|
1800
|
+
"0xc67178f2e372532b",
|
|
1801
|
+
"0xca273eceea26619c",
|
|
1802
|
+
"0xd186b8c721c0c207",
|
|
1803
|
+
"0xeada7dd6cde0eb1e",
|
|
1804
|
+
"0xf57d4f7fee6ed178",
|
|
1805
|
+
"0x06f067aa72176fba",
|
|
1806
|
+
"0x0a637dc5a2c898a6",
|
|
1807
|
+
"0x113f9804bef90dae",
|
|
1808
|
+
"0x1b710b35131c471b",
|
|
1809
|
+
"0x28db77f523047d84",
|
|
1810
|
+
"0x32caab7b40c72493",
|
|
1811
|
+
"0x3c9ebe0a15c9bebc",
|
|
1812
|
+
"0x431d67c49c100d4c",
|
|
1813
|
+
"0x4cc5d4becb3e42b6",
|
|
1814
|
+
"0x597f299cfc657e2a",
|
|
1815
|
+
"0x5fcb6fab3ad6faec",
|
|
1816
|
+
"0x6c44198c4a475817"
|
|
1817
|
+
].map((n) => BigInt(n))))();
|
|
1818
|
+
var SHA512_Kh = /* @__PURE__ */ (() => K512[0])();
|
|
1819
|
+
var SHA512_Kl = /* @__PURE__ */ (() => K512[1])();
|
|
1820
|
+
var SHA512_W_H = /* @__PURE__ */ new Uint32Array(80);
|
|
1821
|
+
var SHA512_W_L = /* @__PURE__ */ new Uint32Array(80);
|
|
1822
|
+
var SHA2_64B = class extends HashMD {
|
|
1823
|
+
constructor(outputLen) {
|
|
1824
|
+
super(128, outputLen, 16, false);
|
|
1825
|
+
}
|
|
1826
|
+
// prettier-ignore
|
|
1827
|
+
get() {
|
|
1828
|
+
const { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this;
|
|
1829
|
+
return [Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl];
|
|
1830
|
+
}
|
|
1831
|
+
// prettier-ignore
|
|
1832
|
+
set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl) {
|
|
1833
|
+
this.Ah = Ah | 0;
|
|
1834
|
+
this.Al = Al | 0;
|
|
1835
|
+
this.Bh = Bh | 0;
|
|
1836
|
+
this.Bl = Bl | 0;
|
|
1837
|
+
this.Ch = Ch | 0;
|
|
1838
|
+
this.Cl = Cl | 0;
|
|
1839
|
+
this.Dh = Dh | 0;
|
|
1840
|
+
this.Dl = Dl | 0;
|
|
1841
|
+
this.Eh = Eh | 0;
|
|
1842
|
+
this.El = El | 0;
|
|
1843
|
+
this.Fh = Fh | 0;
|
|
1844
|
+
this.Fl = Fl | 0;
|
|
1845
|
+
this.Gh = Gh | 0;
|
|
1846
|
+
this.Gl = Gl | 0;
|
|
1847
|
+
this.Hh = Hh | 0;
|
|
1848
|
+
this.Hl = Hl | 0;
|
|
1849
|
+
}
|
|
1850
|
+
process(view, offset) {
|
|
1851
|
+
for (let i2 = 0; i2 < 16; i2++, offset += 4) {
|
|
1852
|
+
SHA512_W_H[i2] = view.getUint32(offset);
|
|
1853
|
+
SHA512_W_L[i2] = view.getUint32(offset += 4);
|
|
1854
|
+
}
|
|
1855
|
+
for (let i2 = 16; i2 < 80; i2++) {
|
|
1856
|
+
const W15h = SHA512_W_H[i2 - 15] | 0;
|
|
1857
|
+
const W15l = SHA512_W_L[i2 - 15] | 0;
|
|
1858
|
+
const s0h = rotrSH(W15h, W15l, 1) ^ rotrSH(W15h, W15l, 8) ^ shrSH(W15h, W15l, 7);
|
|
1859
|
+
const s0l = rotrSL(W15h, W15l, 1) ^ rotrSL(W15h, W15l, 8) ^ shrSL(W15h, W15l, 7);
|
|
1860
|
+
const W2h = SHA512_W_H[i2 - 2] | 0;
|
|
1861
|
+
const W2l = SHA512_W_L[i2 - 2] | 0;
|
|
1862
|
+
const s1h = rotrSH(W2h, W2l, 19) ^ rotrBH(W2h, W2l, 61) ^ shrSH(W2h, W2l, 6);
|
|
1863
|
+
const s1l = rotrSL(W2h, W2l, 19) ^ rotrBL(W2h, W2l, 61) ^ shrSL(W2h, W2l, 6);
|
|
1864
|
+
const SUMl = add4L(s0l, s1l, SHA512_W_L[i2 - 7], SHA512_W_L[i2 - 16]);
|
|
1865
|
+
const SUMh = add4H(SUMl, s0h, s1h, SHA512_W_H[i2 - 7], SHA512_W_H[i2 - 16]);
|
|
1866
|
+
SHA512_W_H[i2] = SUMh | 0;
|
|
1867
|
+
SHA512_W_L[i2] = SUMl | 0;
|
|
1868
|
+
}
|
|
1869
|
+
let { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this;
|
|
1870
|
+
for (let i2 = 0; i2 < 80; i2++) {
|
|
1871
|
+
const sigma1h = rotrSH(Eh, El, 14) ^ rotrSH(Eh, El, 18) ^ rotrBH(Eh, El, 41);
|
|
1872
|
+
const sigma1l = rotrSL(Eh, El, 14) ^ rotrSL(Eh, El, 18) ^ rotrBL(Eh, El, 41);
|
|
1873
|
+
const CHIh = Eh & Fh ^ ~Eh & Gh;
|
|
1874
|
+
const CHIl = El & Fl ^ ~El & Gl;
|
|
1875
|
+
const T1ll = add5L(Hl, sigma1l, CHIl, SHA512_Kl[i2], SHA512_W_L[i2]);
|
|
1876
|
+
const T1h = add5H(T1ll, Hh, sigma1h, CHIh, SHA512_Kh[i2], SHA512_W_H[i2]);
|
|
1877
|
+
const T1l = T1ll | 0;
|
|
1878
|
+
const sigma0h = rotrSH(Ah, Al, 28) ^ rotrBH(Ah, Al, 34) ^ rotrBH(Ah, Al, 39);
|
|
1879
|
+
const sigma0l = rotrSL(Ah, Al, 28) ^ rotrBL(Ah, Al, 34) ^ rotrBL(Ah, Al, 39);
|
|
1880
|
+
const MAJh = Ah & Bh ^ Ah & Ch ^ Bh & Ch;
|
|
1881
|
+
const MAJl = Al & Bl ^ Al & Cl ^ Bl & Cl;
|
|
1882
|
+
Hh = Gh | 0;
|
|
1883
|
+
Hl = Gl | 0;
|
|
1884
|
+
Gh = Fh | 0;
|
|
1885
|
+
Gl = Fl | 0;
|
|
1886
|
+
Fh = Eh | 0;
|
|
1887
|
+
Fl = El | 0;
|
|
1888
|
+
({ h: Eh, l: El } = add(Dh | 0, Dl | 0, T1h | 0, T1l | 0));
|
|
1889
|
+
Dh = Ch | 0;
|
|
1890
|
+
Dl = Cl | 0;
|
|
1891
|
+
Ch = Bh | 0;
|
|
1892
|
+
Cl = Bl | 0;
|
|
1893
|
+
Bh = Ah | 0;
|
|
1894
|
+
Bl = Al | 0;
|
|
1895
|
+
const All = add3L(T1l, sigma0l, MAJl);
|
|
1896
|
+
Ah = add3H(All, T1h, sigma0h, MAJh);
|
|
1897
|
+
Al = All | 0;
|
|
1898
|
+
}
|
|
1899
|
+
({ h: Ah, l: Al } = add(this.Ah | 0, this.Al | 0, Ah | 0, Al | 0));
|
|
1900
|
+
({ h: Bh, l: Bl } = add(this.Bh | 0, this.Bl | 0, Bh | 0, Bl | 0));
|
|
1901
|
+
({ h: Ch, l: Cl } = add(this.Ch | 0, this.Cl | 0, Ch | 0, Cl | 0));
|
|
1902
|
+
({ h: Dh, l: Dl } = add(this.Dh | 0, this.Dl | 0, Dh | 0, Dl | 0));
|
|
1903
|
+
({ h: Eh, l: El } = add(this.Eh | 0, this.El | 0, Eh | 0, El | 0));
|
|
1904
|
+
({ h: Fh, l: Fl } = add(this.Fh | 0, this.Fl | 0, Fh | 0, Fl | 0));
|
|
1905
|
+
({ h: Gh, l: Gl } = add(this.Gh | 0, this.Gl | 0, Gh | 0, Gl | 0));
|
|
1906
|
+
({ h: Hh, l: Hl } = add(this.Hh | 0, this.Hl | 0, Hh | 0, Hl | 0));
|
|
1907
|
+
this.set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl);
|
|
1908
|
+
}
|
|
1909
|
+
roundClean() {
|
|
1910
|
+
clean(SHA512_W_H, SHA512_W_L);
|
|
1911
|
+
}
|
|
1912
|
+
destroy() {
|
|
1913
|
+
this.destroyed = true;
|
|
1914
|
+
clean(this.buffer);
|
|
1915
|
+
this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
1916
|
+
}
|
|
1917
|
+
};
|
|
1918
|
+
var _SHA512 = class extends SHA2_64B {
|
|
1919
|
+
Ah = SHA512_IV[0] | 0;
|
|
1920
|
+
Al = SHA512_IV[1] | 0;
|
|
1921
|
+
Bh = SHA512_IV[2] | 0;
|
|
1922
|
+
Bl = SHA512_IV[3] | 0;
|
|
1923
|
+
Ch = SHA512_IV[4] | 0;
|
|
1924
|
+
Cl = SHA512_IV[5] | 0;
|
|
1925
|
+
Dh = SHA512_IV[6] | 0;
|
|
1926
|
+
Dl = SHA512_IV[7] | 0;
|
|
1927
|
+
Eh = SHA512_IV[8] | 0;
|
|
1928
|
+
El = SHA512_IV[9] | 0;
|
|
1929
|
+
Fh = SHA512_IV[10] | 0;
|
|
1930
|
+
Fl = SHA512_IV[11] | 0;
|
|
1931
|
+
Gh = SHA512_IV[12] | 0;
|
|
1932
|
+
Gl = SHA512_IV[13] | 0;
|
|
1933
|
+
Hh = SHA512_IV[14] | 0;
|
|
1934
|
+
Hl = SHA512_IV[15] | 0;
|
|
1935
|
+
constructor() {
|
|
1936
|
+
super(64);
|
|
1937
|
+
}
|
|
1938
|
+
};
|
|
1939
|
+
var sha256 = /* @__PURE__ */ createHasher(
|
|
1940
|
+
() => new _SHA256(),
|
|
1941
|
+
/* @__PURE__ */ oidNist(1)
|
|
1942
|
+
);
|
|
1943
|
+
var sha512 = /* @__PURE__ */ createHasher(
|
|
1944
|
+
() => new _SHA512(),
|
|
1945
|
+
/* @__PURE__ */ oidNist(3)
|
|
1946
|
+
);
|
|
1947
|
+
|
|
1948
|
+
// ../../node_modules/.pnpm/@otplib+plugin-crypto-noble@13.4.0/node_modules/@otplib/plugin-crypto-noble/dist/index.js
|
|
1949
|
+
var t = class {
|
|
1950
|
+
name = "noble";
|
|
1951
|
+
hmac(r2, n, a2) {
|
|
1952
|
+
return hmac(r2 === "sha1" ? sha1 : r2 === "sha256" ? sha256 : sha512, n, a2);
|
|
1953
|
+
}
|
|
1954
|
+
randomBytes(r2) {
|
|
1955
|
+
return randomBytes(r2);
|
|
1956
|
+
}
|
|
1957
|
+
constantTimeEqual(r2, n) {
|
|
1958
|
+
return tr(r2, n);
|
|
1959
|
+
}
|
|
1960
|
+
};
|
|
1961
|
+
var A2 = Object.freeze(new t());
|
|
1962
|
+
|
|
1963
|
+
// ../../node_modules/.pnpm/otplib@13.4.0/node_modules/otplib/dist/index.js
|
|
1964
|
+
function c2(t2) {
|
|
1965
|
+
return { secret: t2.secret, strategy: t2.strategy ?? "totp", crypto: t2.crypto ?? A2, base32: t2.base32 ?? d2, algorithm: t2.algorithm ?? "sha1", digits: t2.digits ?? 6, period: t2.period ?? 30, epoch: t2.epoch ?? Math.floor(Date.now() / 1e3), t0: t2.t0 ?? 0, counter: t2.counter, guardrails: t2.guardrails ?? hr(), hooks: t2.hooks };
|
|
1966
|
+
}
|
|
1967
|
+
function O3(t2) {
|
|
1968
|
+
return { ...c2(t2), token: t2.token, epochTolerance: t2.epochTolerance ?? 0, counterTolerance: t2.counterTolerance ?? 0, afterTimeStep: t2.afterTimeStep };
|
|
1969
|
+
}
|
|
1970
|
+
function l(t2, e, r2) {
|
|
1971
|
+
if (t2 === "totp") return r2.totp();
|
|
1972
|
+
if (t2 === "hotp") {
|
|
1973
|
+
if (e === void 0) throw new a("Counter is required for HOTP strategy. Example: { strategy: 'hotp', counter: 0 }");
|
|
1974
|
+
return r2.hotp(e);
|
|
1975
|
+
}
|
|
1976
|
+
throw new a(`Unknown OTP strategy: ${t2}. Valid strategies are 'totp' or 'hotp'.`);
|
|
1977
|
+
}
|
|
1978
|
+
function I2(t2) {
|
|
1979
|
+
let { crypto: e = A2, base32: r2 = d2, length: a2 = 20 } = t2 || {};
|
|
1980
|
+
return Dr({ crypto: e, base32: r2, length: a2 });
|
|
1981
|
+
}
|
|
1982
|
+
function T2(t2) {
|
|
1983
|
+
let { strategy: e = "totp", issuer: r2, label: a2, secret: o, algorithm: i2 = "sha1", digits: s = 6, period: n = 30, counter: p } = t2;
|
|
1984
|
+
return l(e, p, { totp: () => x2({ issuer: r2, label: a2, secret: o, algorithm: i2, digits: s, period: n }), hotp: (y2) => U2({ issuer: r2, label: a2, secret: o, algorithm: i2, digits: s, counter: y2 }) });
|
|
1985
|
+
}
|
|
1986
|
+
function d3(t2) {
|
|
1987
|
+
let e = O3(t2), { secret: r2, token: a2, crypto: o, base32: i2, algorithm: s, digits: n, hooks: p } = e, y2 = { secret: r2, token: a2, crypto: o, base32: i2, algorithm: s, digits: n, hooks: p };
|
|
1988
|
+
return l(e.strategy, e.counter, { totp: () => ie({ ...y2, period: e.period, epoch: e.epoch, t0: e.t0, epochTolerance: e.epochTolerance, afterTimeStep: e.afterTimeStep, guardrails: e.guardrails }), hotp: (f2) => Y2({ ...y2, counter: f2, counterTolerance: e.counterTolerance, guardrails: e.guardrails }) });
|
|
1989
|
+
}
|
|
1990
|
+
|
|
1991
|
+
// ../core/dist/controllers/auth.js
|
|
569
1992
|
import { z, flattenError } from "zod";
|
|
570
1993
|
|
|
571
1994
|
// ../core/dist/media/index.js
|
|
572
1995
|
import multer from "multer";
|
|
573
1996
|
|
|
574
1997
|
// ../core/dist/lib/encrypt.js
|
|
575
|
-
import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
|
|
1998
|
+
import { createCipheriv, createDecipheriv, randomBytes as randomBytes2 } from "crypto";
|
|
576
1999
|
var ALGORITHM = "aes-256-gcm";
|
|
577
2000
|
var KEY_LENGTH = 32;
|
|
578
2001
|
var IV_LENGTH = 12;
|
|
579
2002
|
var TAG_LENGTH = 16;
|
|
580
2003
|
function getKey() {
|
|
581
2004
|
const raw = process.env.PLANK_ENCRYPTION_KEY;
|
|
582
|
-
if (!raw)
|
|
2005
|
+
if (!raw) {
|
|
2006
|
+
if (process.env.NODE_ENV === "production") {
|
|
2007
|
+
throw new Error("PLANK_ENCRYPTION_KEY is required in production");
|
|
2008
|
+
}
|
|
583
2009
|
return null;
|
|
2010
|
+
}
|
|
584
2011
|
const buf = Buffer.from(raw, "hex");
|
|
585
2012
|
if (buf.length !== KEY_LENGTH) {
|
|
2013
|
+
if (process.env.NODE_ENV === "production") {
|
|
2014
|
+
throw new Error("PLANK_ENCRYPTION_KEY must be 64 hex chars (32 bytes) in production");
|
|
2015
|
+
}
|
|
586
2016
|
console.warn("[plank] PLANK_ENCRYPTION_KEY must be 64 hex chars (32 bytes). Falling back to plaintext storage.");
|
|
587
2017
|
return null;
|
|
588
2018
|
}
|
|
@@ -592,7 +2022,7 @@ function encrypt(plaintext) {
|
|
|
592
2022
|
const key = getKey();
|
|
593
2023
|
if (!key)
|
|
594
2024
|
return plaintext;
|
|
595
|
-
const iv =
|
|
2025
|
+
const iv = randomBytes2(IV_LENGTH);
|
|
596
2026
|
const cipher = createCipheriv(ALGORITHM, key, iv);
|
|
597
2027
|
const encrypted = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
|
|
598
2028
|
const tag = cipher.getAuthTag();
|
|
@@ -624,7 +2054,7 @@ function isSensitive(namespace, key) {
|
|
|
624
2054
|
}
|
|
625
2055
|
async function getSettings(namespace) {
|
|
626
2056
|
const { rows } = await pool_default.query("SELECT key, value FROM plank_settings WHERE namespace = $1", [namespace]);
|
|
627
|
-
return Object.fromEntries(rows.map((
|
|
2057
|
+
return Object.fromEntries(rows.map((r2) => [r2.key, isSensitive(namespace, r2.key) ? decrypt(r2.value) : r2.value]));
|
|
628
2058
|
}
|
|
629
2059
|
async function getSetting(namespace, key) {
|
|
630
2060
|
const { rows } = await pool_default.query("SELECT value FROM plank_settings WHERE namespace = $1 AND key = $2", [namespace, key]);
|
|
@@ -639,7 +2069,7 @@ async function setSettings(namespace, values) {
|
|
|
639
2069
|
key,
|
|
640
2070
|
value: isSensitive(namespace, key) ? encrypt(value) : value
|
|
641
2071
|
}));
|
|
642
|
-
const placeholders = entries.map((
|
|
2072
|
+
const placeholders = entries.map((_3, i2) => `($1, $${i2 * 2 + 2}, $${i2 * 2 + 3})`).join(", ");
|
|
643
2073
|
const params = [namespace];
|
|
644
2074
|
for (const { key, value } of entries) {
|
|
645
2075
|
params.push(key, value);
|
|
@@ -651,8 +2081,8 @@ async function setSettings(namespace, values) {
|
|
|
651
2081
|
|
|
652
2082
|
// ../core/dist/media/providers/local.js
|
|
653
2083
|
import { writeFile, mkdir } from "fs/promises";
|
|
654
|
-
import { join as
|
|
655
|
-
import { randomBytes as
|
|
2084
|
+
import { join as join3, extname } from "path";
|
|
2085
|
+
import { randomBytes as randomBytes3 } from "crypto";
|
|
656
2086
|
async function uploadsDir() {
|
|
657
2087
|
const fromSettings = await getSetting("media", "local.uploads_dir");
|
|
658
2088
|
return fromSettings ?? process.env.PLANK_UPLOADS_DIR ?? "public/uploads";
|
|
@@ -664,27 +2094,27 @@ async function publicUrl() {
|
|
|
664
2094
|
var localProvider = {
|
|
665
2095
|
async upload(file, options) {
|
|
666
2096
|
const base_dir = await uploadsDir();
|
|
667
|
-
const subdir = options?.prefix ?
|
|
2097
|
+
const subdir = options?.prefix ? join3(base_dir, options.prefix) : base_dir;
|
|
668
2098
|
await mkdir(subdir, { recursive: true });
|
|
669
2099
|
const ext = extname(file.originalname);
|
|
670
|
-
const filename = `${
|
|
2100
|
+
const filename = `${randomBytes3(16).toString("hex")}${ext}`;
|
|
671
2101
|
const key = options?.prefix ? `${options.prefix}/${filename}` : filename;
|
|
672
|
-
await writeFile(
|
|
2102
|
+
await writeFile(join3(base_dir, key), file.buffer);
|
|
673
2103
|
const base = await publicUrl();
|
|
674
2104
|
return { url: `${base}/uploads/${key}`, key };
|
|
675
2105
|
},
|
|
676
2106
|
async uploadRaw(buffer, exactKey, mimeType) {
|
|
677
2107
|
const base_dir = await uploadsDir();
|
|
678
|
-
const dir =
|
|
2108
|
+
const dir = join3(base_dir, exactKey.split("/").slice(0, -1).join("/"));
|
|
679
2109
|
await mkdir(dir, { recursive: true });
|
|
680
|
-
await writeFile(
|
|
2110
|
+
await writeFile(join3(base_dir, exactKey), buffer);
|
|
681
2111
|
const base = await publicUrl();
|
|
682
2112
|
return { url: `${base}/uploads/${exactKey}`, key: exactKey };
|
|
683
2113
|
},
|
|
684
2114
|
async delete(key) {
|
|
685
2115
|
const { unlink } = await import("fs/promises");
|
|
686
2116
|
const dir = await uploadsDir();
|
|
687
|
-
await unlink(
|
|
2117
|
+
await unlink(join3(dir, key));
|
|
688
2118
|
},
|
|
689
2119
|
async getUrl(key) {
|
|
690
2120
|
const base = await publicUrl();
|
|
@@ -696,7 +2126,7 @@ var localProvider = {
|
|
|
696
2126
|
import { S3Client, PutObjectCommand, DeleteObjectCommand } from "@aws-sdk/client-s3";
|
|
697
2127
|
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
|
|
698
2128
|
import { extname as extname2 } from "path";
|
|
699
|
-
import { randomBytes as
|
|
2129
|
+
import { randomBytes as randomBytes4 } from "crypto";
|
|
700
2130
|
async function getConfig() {
|
|
701
2131
|
const [accessKeyId, secretAccessKey, region, bucket, pathPrefix, publicUrl2] = await Promise.all([
|
|
702
2132
|
getSetting("media", "s3.access_key_id"),
|
|
@@ -719,7 +2149,7 @@ function buildClient(cfg) {
|
|
|
719
2149
|
}
|
|
720
2150
|
function buildKey(cfg, filename, prefix) {
|
|
721
2151
|
const ext = extname2(filename);
|
|
722
|
-
const name = `${
|
|
2152
|
+
const name = `${randomBytes4(16).toString("hex")}${ext}`;
|
|
723
2153
|
const parts = [cfg.pathPrefix?.replace(/\/$/, ""), prefix, name].filter(Boolean);
|
|
724
2154
|
return parts.join("/");
|
|
725
2155
|
}
|
|
@@ -773,7 +2203,7 @@ var s3Provider = {
|
|
|
773
2203
|
import { S3Client as S3Client2, PutObjectCommand as PutObjectCommand2, DeleteObjectCommand as DeleteObjectCommand2 } from "@aws-sdk/client-s3";
|
|
774
2204
|
import { getSignedUrl as getSignedUrl2 } from "@aws-sdk/s3-request-presigner";
|
|
775
2205
|
import { extname as extname3 } from "path";
|
|
776
|
-
import { randomBytes as
|
|
2206
|
+
import { randomBytes as randomBytes5 } from "crypto";
|
|
777
2207
|
async function getConfig2() {
|
|
778
2208
|
const [accessKeyId, secretAccessKey, accountId, bucket, pathPrefix, publicUrl2] = await Promise.all([
|
|
779
2209
|
getSetting("media", "r2.access_key_id"),
|
|
@@ -799,7 +2229,7 @@ function buildClient2(cfg) {
|
|
|
799
2229
|
}
|
|
800
2230
|
function buildKey2(cfg, filename, prefix) {
|
|
801
2231
|
const ext = extname3(filename);
|
|
802
|
-
const name = `${
|
|
2232
|
+
const name = `${randomBytes5(16).toString("hex")}${ext}`;
|
|
803
2233
|
const parts = [cfg.pathPrefix?.replace(/\/$/, ""), prefix, name].filter(Boolean);
|
|
804
2234
|
return parts.join("/");
|
|
805
2235
|
}
|
|
@@ -873,57 +2303,78 @@ var LoginSchema = z.object({
|
|
|
873
2303
|
email: z.email(),
|
|
874
2304
|
password: z.string().min(1)
|
|
875
2305
|
});
|
|
2306
|
+
var Login2FASchema = z.object({
|
|
2307
|
+
challengeToken: z.string().min(1),
|
|
2308
|
+
code: z.string().trim().length(6)
|
|
2309
|
+
});
|
|
876
2310
|
var RegisterSchema = z.object({
|
|
877
2311
|
email: z.email(),
|
|
878
2312
|
password: z.string().min(8)
|
|
879
2313
|
});
|
|
880
|
-
var loginAttempts = /* @__PURE__ */ new Map();
|
|
881
|
-
var RATE_LIMIT_MAX = 10;
|
|
882
2314
|
var RATE_LIMIT_WINDOW_MS = 15 * 60 * 1e3;
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
}
|
|
890
|
-
if (entry.count >= RATE_LIMIT_MAX)
|
|
891
|
-
return false;
|
|
892
|
-
entry.count++;
|
|
893
|
-
return true;
|
|
2315
|
+
var LOGIN_RATE_LIMIT_MAX = 10;
|
|
2316
|
+
var LOGIN_2FA_RATE_LIMIT_MAX = 5;
|
|
2317
|
+
var ACCESS_TOKEN_COOKIE = "plank_session";
|
|
2318
|
+
var ACCESS_TOKEN_EXPIRES_SECONDS = 60 * 15;
|
|
2319
|
+
function isProduction() {
|
|
2320
|
+
return process.env.NODE_ENV === "production";
|
|
894
2321
|
}
|
|
895
|
-
function
|
|
896
|
-
|
|
2322
|
+
function setSessionCookie(res, token) {
|
|
2323
|
+
res.cookie(ACCESS_TOKEN_COOKIE, token, {
|
|
2324
|
+
httpOnly: true,
|
|
2325
|
+
secure: isProduction(),
|
|
2326
|
+
sameSite: "lax",
|
|
2327
|
+
path: "/",
|
|
2328
|
+
maxAge: ACCESS_TOKEN_EXPIRES_SECONDS * 1e3
|
|
2329
|
+
});
|
|
897
2330
|
}
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
}
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
2331
|
+
function clearSessionCookie(res) {
|
|
2332
|
+
res.clearCookie(ACCESS_TOKEN_COOKIE, {
|
|
2333
|
+
httpOnly: true,
|
|
2334
|
+
secure: isProduction(),
|
|
2335
|
+
sameSite: "lax",
|
|
2336
|
+
path: "/"
|
|
2337
|
+
});
|
|
2338
|
+
}
|
|
2339
|
+
async function consumeRateLimit(scope, rateKey, max) {
|
|
2340
|
+
const resetAt = new Date(Date.now() + RATE_LIMIT_WINDOW_MS);
|
|
2341
|
+
const { rows } = await pool_default.query(`INSERT INTO plank_auth_rate_limits (id, scope, rate_key, count, reset_at)
|
|
2342
|
+
VALUES ($1, $2, $3, 1, $4)
|
|
2343
|
+
ON CONFLICT (scope, rate_key)
|
|
2344
|
+
DO UPDATE
|
|
2345
|
+
SET count = CASE
|
|
2346
|
+
WHEN plank_auth_rate_limits.reset_at <= NOW() THEN 1
|
|
2347
|
+
ELSE plank_auth_rate_limits.count + 1
|
|
2348
|
+
END,
|
|
2349
|
+
reset_at = CASE
|
|
2350
|
+
WHEN plank_auth_rate_limits.reset_at <= NOW() THEN $4
|
|
2351
|
+
ELSE plank_auth_rate_limits.reset_at
|
|
2352
|
+
END,
|
|
2353
|
+
updated_at = NOW()
|
|
2354
|
+
RETURNING count, reset_at`, [createId(), scope, rateKey, resetAt]);
|
|
2355
|
+
return (rows[0]?.count ?? max + 1) <= max;
|
|
2356
|
+
}
|
|
2357
|
+
async function clearRateLimit(scope, rateKey) {
|
|
2358
|
+
await pool_default.query("DELETE FROM plank_auth_rate_limits WHERE scope = $1 AND rate_key = $2", [
|
|
2359
|
+
scope,
|
|
2360
|
+
rateKey
|
|
2361
|
+
]);
|
|
2362
|
+
}
|
|
2363
|
+
function buildAccessToken(payload) {
|
|
2364
|
+
return jwt.sign(payload, process.env.PLANK_JWT_SECRET, { expiresIn: "15m" });
|
|
2365
|
+
}
|
|
2366
|
+
function buildChallengeToken(payload) {
|
|
2367
|
+
return jwt.sign(payload, process.env.PLANK_JWT_SECRET, { expiresIn: "5m" });
|
|
2368
|
+
}
|
|
2369
|
+
async function buildAuthPayload(user) {
|
|
918
2370
|
const { rows: roleRows } = await pool_default.query("SELECT id, name, permissions FROM plank_roles WHERE id = $1", [user.role_id]);
|
|
919
|
-
clearRateLimit(ip);
|
|
920
2371
|
let avatarUrl = user.avatar_url;
|
|
921
2372
|
if (avatarUrl && !avatarUrl.startsWith("http")) {
|
|
922
2373
|
const provider = await getProvider();
|
|
923
2374
|
avatarUrl = await provider.getUrl(avatarUrl);
|
|
924
2375
|
}
|
|
925
|
-
const token =
|
|
926
|
-
|
|
2376
|
+
const token = buildAccessToken({ sub: user.id, roleId: user.role_id, sv: user.session_version });
|
|
2377
|
+
return {
|
|
927
2378
|
token,
|
|
928
2379
|
user: {
|
|
929
2380
|
id: user.id,
|
|
@@ -935,10 +2386,118 @@ async function login(req, res) {
|
|
|
935
2386
|
avatarUrl,
|
|
936
2387
|
jobTitle: user.job_title,
|
|
937
2388
|
organization: user.organization,
|
|
938
|
-
country: user.country
|
|
2389
|
+
country: user.country,
|
|
2390
|
+
twoFactorEnabled: user.two_factor_enabled
|
|
939
2391
|
}
|
|
2392
|
+
};
|
|
2393
|
+
}
|
|
2394
|
+
async function login(req, res) {
|
|
2395
|
+
const ip = req.ip ?? "unknown";
|
|
2396
|
+
const parsed = LoginSchema.safeParse(req.body);
|
|
2397
|
+
if (!parsed.success) {
|
|
2398
|
+
res.status(400).json({ errors: flattenError(parsed.error, (i2) => i2.message) });
|
|
2399
|
+
return;
|
|
2400
|
+
}
|
|
2401
|
+
const { email, password } = parsed.data;
|
|
2402
|
+
const rateKey = `${ip}:${email.toLowerCase()}`;
|
|
2403
|
+
if (!await consumeRateLimit("login", rateKey, LOGIN_RATE_LIMIT_MAX)) {
|
|
2404
|
+
res.status(429).json({ error: "Too many login attempts. Try again in 15 minutes." });
|
|
2405
|
+
return;
|
|
2406
|
+
}
|
|
2407
|
+
const { rows } = await pool_default.query(`SELECT id, email, password, role_id, first_name, last_name, avatar_url, job_title, organization, country, two_factor_enabled, two_factor_secret, session_version
|
|
2408
|
+
FROM plank_users
|
|
2409
|
+
WHERE email = $1`, [email]);
|
|
2410
|
+
const user = rows[0];
|
|
2411
|
+
if (!user || !await bcrypt.compare(password, user.password)) {
|
|
2412
|
+
res.status(401).json({ error: "Invalid credentials" });
|
|
2413
|
+
return;
|
|
2414
|
+
}
|
|
2415
|
+
await clearRateLimit("login", rateKey);
|
|
2416
|
+
if (user.two_factor_enabled && user.two_factor_secret) {
|
|
2417
|
+
const challengeToken = buildChallengeToken({
|
|
2418
|
+
sub: user.id,
|
|
2419
|
+
roleId: user.role_id,
|
|
2420
|
+
sv: user.session_version,
|
|
2421
|
+
twoFactor: true,
|
|
2422
|
+
jti: createId()
|
|
2423
|
+
});
|
|
2424
|
+
res.json({ requiresTwoFactor: true, challengeToken });
|
|
2425
|
+
return;
|
|
2426
|
+
}
|
|
2427
|
+
const auth = await buildAuthPayload(user);
|
|
2428
|
+
setSessionCookie(res, auth.token);
|
|
2429
|
+
res.json({
|
|
2430
|
+
requiresTwoFactor: false,
|
|
2431
|
+
user: auth.user
|
|
2432
|
+
});
|
|
2433
|
+
}
|
|
2434
|
+
async function loginWithTwoFactor(req, res) {
|
|
2435
|
+
const ip = req.ip ?? "unknown";
|
|
2436
|
+
const parsed = Login2FASchema.safeParse(req.body);
|
|
2437
|
+
if (!parsed.success) {
|
|
2438
|
+
res.status(400).json({ errors: flattenError(parsed.error, (i2) => i2.message) });
|
|
2439
|
+
return;
|
|
2440
|
+
}
|
|
2441
|
+
let payload;
|
|
2442
|
+
try {
|
|
2443
|
+
payload = jwt.verify(parsed.data.challengeToken, process.env.PLANK_JWT_SECRET);
|
|
2444
|
+
} catch {
|
|
2445
|
+
res.status(401).json({ error: "Invalid or expired 2FA challenge" });
|
|
2446
|
+
return;
|
|
2447
|
+
}
|
|
2448
|
+
if (!payload.twoFactor) {
|
|
2449
|
+
res.status(400).json({ error: "Invalid 2FA challenge token" });
|
|
2450
|
+
return;
|
|
2451
|
+
}
|
|
2452
|
+
const rateKey = `${ip}:${payload.sub}:${payload.jti ?? "nojti"}`;
|
|
2453
|
+
if (!await consumeRateLimit("login-2fa", rateKey, LOGIN_2FA_RATE_LIMIT_MAX)) {
|
|
2454
|
+
res.status(429).json({ error: "Too many 2FA attempts. Try again in 15 minutes." });
|
|
2455
|
+
return;
|
|
2456
|
+
}
|
|
2457
|
+
const { rows } = await pool_default.query(`SELECT id, email, role_id, first_name, last_name, avatar_url, job_title, organization, country, two_factor_enabled, two_factor_secret, password, session_version
|
|
2458
|
+
FROM plank_users WHERE id = $1`, [payload.sub]);
|
|
2459
|
+
const user = rows[0];
|
|
2460
|
+
if (!user || !user.two_factor_enabled || !user.two_factor_secret) {
|
|
2461
|
+
res.status(401).json({ error: "2FA is not enabled for this account" });
|
|
2462
|
+
return;
|
|
2463
|
+
}
|
|
2464
|
+
if (user.session_version !== payload.sv) {
|
|
2465
|
+
res.status(401).json({ error: "2FA challenge expired. Start login again." });
|
|
2466
|
+
return;
|
|
2467
|
+
}
|
|
2468
|
+
const result = d3({
|
|
2469
|
+
token: parsed.data.code,
|
|
2470
|
+
secret: decrypt(user.two_factor_secret)
|
|
2471
|
+
});
|
|
2472
|
+
if (!result.valid) {
|
|
2473
|
+
res.status(401).json({ error: "Invalid verification code" });
|
|
2474
|
+
return;
|
|
2475
|
+
}
|
|
2476
|
+
await clearRateLimit("login-2fa", rateKey);
|
|
2477
|
+
const auth = await buildAuthPayload(user);
|
|
2478
|
+
setSessionCookie(res, auth.token);
|
|
2479
|
+
res.json({
|
|
2480
|
+
requiresTwoFactor: false,
|
|
2481
|
+
user: auth.user
|
|
940
2482
|
});
|
|
941
2483
|
}
|
|
2484
|
+
async function logout(req, res) {
|
|
2485
|
+
const cookieHeader = req.headers.cookie ?? "";
|
|
2486
|
+
const raw = cookieHeader.split(";").map((c3) => c3.trim()).find((c3) => c3.startsWith(`${ACCESS_TOKEN_COOKIE}=`))?.slice(`${ACCESS_TOKEN_COOKIE}=`.length);
|
|
2487
|
+
if (raw) {
|
|
2488
|
+
try {
|
|
2489
|
+
const payload = jwt.verify(decodeURIComponent(raw), process.env.PLANK_JWT_SECRET);
|
|
2490
|
+
if (payload.sub) {
|
|
2491
|
+
await pool_default.query("UPDATE plank_users SET session_version = session_version + 1 WHERE id = $1", [payload.sub]);
|
|
2492
|
+
}
|
|
2493
|
+
} catch {
|
|
2494
|
+
}
|
|
2495
|
+
}
|
|
2496
|
+
clearSessionCookie(res);
|
|
2497
|
+
const ip = req.ip ?? "unknown";
|
|
2498
|
+
await pool_default.query("DELETE FROM plank_auth_rate_limits WHERE rate_key LIKE $1", [`${ip}:%`]);
|
|
2499
|
+
res.status(204).end();
|
|
2500
|
+
}
|
|
942
2501
|
async function setup(_req, res) {
|
|
943
2502
|
const { rows } = await pool_default.query("SELECT COUNT(*) as count FROM plank_users");
|
|
944
2503
|
res.json({ needsSetup: parseInt(rows[0].count) === 0 });
|
|
@@ -951,7 +2510,7 @@ async function register(req, res) {
|
|
|
951
2510
|
}
|
|
952
2511
|
const parsed = RegisterSchema.safeParse(req.body);
|
|
953
2512
|
if (!parsed.success) {
|
|
954
|
-
res.status(400).json({ errors: flattenError(parsed.error, (
|
|
2513
|
+
res.status(400).json({ errors: flattenError(parsed.error, (i2) => i2.message) });
|
|
955
2514
|
return;
|
|
956
2515
|
}
|
|
957
2516
|
const { email, password } = parsed.data;
|
|
@@ -966,6 +2525,8 @@ async function register(req, res) {
|
|
|
966
2525
|
var router = Router();
|
|
967
2526
|
router.get("/setup", setup);
|
|
968
2527
|
router.post("/login", login);
|
|
2528
|
+
router.post("/login/2fa", loginWithTwoFactor);
|
|
2529
|
+
router.post("/logout", logout);
|
|
969
2530
|
router.post("/register", register);
|
|
970
2531
|
var auth_default = router;
|
|
971
2532
|
|
|
@@ -974,15 +2535,37 @@ import { Router as Router2 } from "express";
|
|
|
974
2535
|
|
|
975
2536
|
// ../core/dist/middlewares/authenticate.js
|
|
976
2537
|
import jwt2 from "jsonwebtoken";
|
|
977
|
-
function
|
|
2538
|
+
function cookieValue(raw, key) {
|
|
2539
|
+
if (!raw)
|
|
2540
|
+
return null;
|
|
2541
|
+
const parts = raw.split(";");
|
|
2542
|
+
for (const part of parts) {
|
|
2543
|
+
const [k3, ...rest] = part.trim().split("=");
|
|
2544
|
+
if (k3 === key)
|
|
2545
|
+
return decodeURIComponent(rest.join("="));
|
|
2546
|
+
}
|
|
2547
|
+
return null;
|
|
2548
|
+
}
|
|
2549
|
+
async function authenticate(req, res, next) {
|
|
978
2550
|
const header = req.headers.authorization;
|
|
979
|
-
|
|
2551
|
+
const bearer = header?.startsWith("Bearer ") ? header.slice(7) : null;
|
|
2552
|
+
const cookieToken = cookieValue(req.headers.cookie, "plank_session");
|
|
2553
|
+
const token = bearer ?? cookieToken;
|
|
2554
|
+
if (!token) {
|
|
980
2555
|
res.status(401).json({ error: "Unauthorized" });
|
|
981
2556
|
return;
|
|
982
2557
|
}
|
|
983
|
-
const token = header.slice(7);
|
|
984
2558
|
try {
|
|
985
2559
|
const payload = jwt2.verify(token, process.env.PLANK_JWT_SECRET);
|
|
2560
|
+
if (typeof payload.sv !== "number") {
|
|
2561
|
+
res.status(401).json({ error: "Invalid session token" });
|
|
2562
|
+
return;
|
|
2563
|
+
}
|
|
2564
|
+
const { rows } = await pool_default.query("SELECT session_version FROM plank_users WHERE id = $1", [payload.sub]);
|
|
2565
|
+
if (!rows[0] || rows[0].session_version !== payload.sv) {
|
|
2566
|
+
res.status(401).json({ error: "Session has been revoked" });
|
|
2567
|
+
return;
|
|
2568
|
+
}
|
|
986
2569
|
req.user = { id: payload.sub, roleId: payload.roleId };
|
|
987
2570
|
next();
|
|
988
2571
|
} catch {
|
|
@@ -1161,22 +2744,22 @@ async function syncInverseFields(savedCT, prevCT) {
|
|
|
1161
2744
|
if (relatedCTCache.has(tableName))
|
|
1162
2745
|
return relatedCTCache.get(tableName) ?? null;
|
|
1163
2746
|
const all = await findAllContentTypes();
|
|
1164
|
-
const ct = all.find((
|
|
2747
|
+
const ct = all.find((c3) => c3.tableName === tableName) ?? null;
|
|
1165
2748
|
relatedCTCache.set(tableName, ct);
|
|
1166
2749
|
return ct;
|
|
1167
2750
|
}
|
|
1168
|
-
const prevRelFields = new Map((prevCT?.fields ?? []).filter((
|
|
1169
|
-
const nextRelFields = savedCT.fields.filter((
|
|
2751
|
+
const prevRelFields = new Map((prevCT?.fields ?? []).filter((f2) => f2.type === "relation" && f2.relationType !== "one-to-many").map((f2) => [f2.name, f2]));
|
|
2752
|
+
const nextRelFields = savedCT.fields.filter((f2) => f2.type === "relation" && f2.relationType !== "one-to-many");
|
|
1170
2753
|
for (const [fieldName, prevField] of prevRelFields) {
|
|
1171
2754
|
if (!prevField.relatedTable)
|
|
1172
2755
|
continue;
|
|
1173
|
-
const nextField = savedCT.fields.find((
|
|
2756
|
+
const nextField = savedCT.fields.find((f2) => f2.name === fieldName);
|
|
1174
2757
|
const targetChanged = nextField?.relatedTable !== prevField.relatedTable;
|
|
1175
2758
|
if (!nextField || targetChanged) {
|
|
1176
2759
|
const relatedCT = await getRelatedCT(prevField.relatedTable);
|
|
1177
2760
|
if (!relatedCT)
|
|
1178
2761
|
continue;
|
|
1179
|
-
const updated = relatedCT.fields.filter((
|
|
2762
|
+
const updated = relatedCT.fields.filter((f2) => !(f2.type === "relation" && f2.relationType === inverseRelationType(prevField.relationType ?? "many-to-one") && f2.relatedTable === savedCT.tableName && f2.relatedField === fieldName));
|
|
1180
2763
|
if (updated.length !== relatedCT.fields.length) {
|
|
1181
2764
|
await updateContentType(relatedCT.slug, { ...relatedCT, fields: updated });
|
|
1182
2765
|
}
|
|
@@ -1189,9 +2772,9 @@ async function syncInverseFields(savedCT, prevCT) {
|
|
|
1189
2772
|
if (!relatedCT)
|
|
1190
2773
|
continue;
|
|
1191
2774
|
const invType = inverseRelationType(field.relationType ?? "many-to-one");
|
|
1192
|
-
const existingInvIdx = relatedCT.fields.findIndex((
|
|
2775
|
+
const existingInvIdx = relatedCT.fields.findIndex((f2) => f2.type === "relation" && f2.relationType === invType && f2.relatedTable === savedCT.tableName && f2.relatedField === field.name);
|
|
1193
2776
|
const invField = {
|
|
1194
|
-
name: existingInvIdx >= 0 ? relatedCT.fields[existingInvIdx].name : inverseFieldName(savedCT.tableName, field.name, relatedCT.fields.map((
|
|
2777
|
+
name: existingInvIdx >= 0 ? relatedCT.fields[existingInvIdx].name : inverseFieldName(savedCT.tableName, field.name, relatedCT.fields.map((f2) => f2.name)),
|
|
1195
2778
|
type: "relation",
|
|
1196
2779
|
relationType: invType,
|
|
1197
2780
|
relatedTable: savedCT.tableName,
|
|
@@ -1200,7 +2783,7 @@ async function syncInverseFields(savedCT, prevCT) {
|
|
|
1200
2783
|
};
|
|
1201
2784
|
let updatedFields;
|
|
1202
2785
|
if (existingInvIdx >= 0) {
|
|
1203
|
-
updatedFields = relatedCT.fields.map((
|
|
2786
|
+
updatedFields = relatedCT.fields.map((f2, i2) => i2 === existingInvIdx ? invField : f2);
|
|
1204
2787
|
} else {
|
|
1205
2788
|
updatedFields = [...relatedCT.fields, invField];
|
|
1206
2789
|
}
|
|
@@ -1210,7 +2793,7 @@ async function syncInverseFields(savedCT, prevCT) {
|
|
|
1210
2793
|
async function removeRelationDependencies(deletedTable) {
|
|
1211
2794
|
const all = await findAllContentTypes();
|
|
1212
2795
|
for (const ct of all) {
|
|
1213
|
-
const toRemove = ct.fields.filter((
|
|
2796
|
+
const toRemove = ct.fields.filter((f2) => f2.type === "relation" && f2.relatedTable === deletedTable.tableName);
|
|
1214
2797
|
if (toRemove.length === 0)
|
|
1215
2798
|
continue;
|
|
1216
2799
|
for (const field of toRemove) {
|
|
@@ -1226,7 +2809,7 @@ async function removeRelationDependencies(deletedTable) {
|
|
|
1226
2809
|
await pool_default.query(`DROP TABLE IF EXISTS ${quoteIdentifier(jt)}`);
|
|
1227
2810
|
}
|
|
1228
2811
|
}
|
|
1229
|
-
const filtered = ct.fields.filter((
|
|
2812
|
+
const filtered = ct.fields.filter((f2) => !(f2.type === "relation" && f2.relatedTable === deletedTable.tableName));
|
|
1230
2813
|
await updateContentType(ct.slug, { ...ct, fields: filtered });
|
|
1231
2814
|
}
|
|
1232
2815
|
}
|
|
@@ -1245,7 +2828,7 @@ var getContentType = async (req, res) => {
|
|
|
1245
2828
|
var createContentType = async (req, res) => {
|
|
1246
2829
|
const parsed = CreateContentTypeSchema.safeParse(req.body);
|
|
1247
2830
|
if (!parsed.success) {
|
|
1248
|
-
res.status(400).json({ errors: flattenError2(parsed.error, (
|
|
2831
|
+
res.status(400).json({ errors: flattenError2(parsed.error, (i2) => i2.message) });
|
|
1249
2832
|
return;
|
|
1250
2833
|
}
|
|
1251
2834
|
const reservedErrors = findReservedIdentifierErrors(parsed.data);
|
|
@@ -1270,7 +2853,7 @@ var updateContentType2 = async (req, res) => {
|
|
|
1270
2853
|
}
|
|
1271
2854
|
const parsed = ContentTypeSchema.safeParse(req.body);
|
|
1272
2855
|
if (!parsed.success) {
|
|
1273
|
-
res.status(400).json({ errors: flattenError2(parsed.error, (
|
|
2856
|
+
res.status(400).json({ errors: flattenError2(parsed.error, (i2) => i2.message) });
|
|
1274
2857
|
return;
|
|
1275
2858
|
}
|
|
1276
2859
|
const reservedErrors = findReservedIdentifierErrors(parsed.data);
|
|
@@ -1322,7 +2905,7 @@ async function listWebhooks(_req, res) {
|
|
|
1322
2905
|
async function createWebhook(req, res) {
|
|
1323
2906
|
const parsed = CreateWebhookSchema.safeParse(req.body);
|
|
1324
2907
|
if (!parsed.success) {
|
|
1325
|
-
res.status(400).json({ errors: flattenError3(parsed.error, (
|
|
2908
|
+
res.status(400).json({ errors: flattenError3(parsed.error, (i2) => i2.message) });
|
|
1326
2909
|
return;
|
|
1327
2910
|
}
|
|
1328
2911
|
const { name, url, events } = parsed.data;
|
|
@@ -1365,22 +2948,22 @@ function resolveLocalizedRow(row, ct, locale, fallbacks = []) {
|
|
|
1365
2948
|
const localized = row.localized && typeof row.localized === "object" ? row.localized : {};
|
|
1366
2949
|
const resolved = { ...row };
|
|
1367
2950
|
const localizableTypes = /* @__PURE__ */ new Set(["string", "text", "richtext", "uid"]);
|
|
1368
|
-
for (const
|
|
1369
|
-
if (!localizableTypes.has(
|
|
2951
|
+
for (const f2 of ct.fields) {
|
|
2952
|
+
if (!localizableTypes.has(f2.type))
|
|
1370
2953
|
continue;
|
|
1371
2954
|
let val = void 0;
|
|
1372
|
-
if (locale && localized[locale] && localized[locale][
|
|
1373
|
-
val = localized[locale][
|
|
2955
|
+
if (locale && localized[locale] && localized[locale][f2.name] !== void 0) {
|
|
2956
|
+
val = localized[locale][f2.name];
|
|
1374
2957
|
} else {
|
|
1375
2958
|
for (const fb of fallbacks) {
|
|
1376
|
-
if (localized[fb] && localized[fb][
|
|
1377
|
-
val = localized[fb][
|
|
2959
|
+
if (localized[fb] && localized[fb][f2.name] !== void 0) {
|
|
2960
|
+
val = localized[fb][f2.name];
|
|
1378
2961
|
break;
|
|
1379
2962
|
}
|
|
1380
2963
|
}
|
|
1381
2964
|
}
|
|
1382
2965
|
if (val !== void 0)
|
|
1383
|
-
resolved[
|
|
2966
|
+
resolved[f2.name] = val;
|
|
1384
2967
|
}
|
|
1385
2968
|
return resolved;
|
|
1386
2969
|
}
|
|
@@ -1428,7 +3011,7 @@ async function syncManyToMany(entryId, tableName, field, targetIds) {
|
|
|
1428
3011
|
await pool_default.query(`DELETE FROM ${quoteIdentifier(jt)} WHERE source_id = $1`, [entryId]);
|
|
1429
3012
|
if (targetIds.length === 0)
|
|
1430
3013
|
return;
|
|
1431
|
-
const placeholders = targetIds.map((
|
|
3014
|
+
const placeholders = targetIds.map((_3, i2) => `($1, $${i2 + 2})`).join(", ");
|
|
1432
3015
|
await pool_default.query(`INSERT INTO ${quoteIdentifier(jt)} (source_id, target_id) VALUES ${placeholders} ON CONFLICT DO NOTHING`, [entryId, ...targetIds]);
|
|
1433
3016
|
}
|
|
1434
3017
|
async function isUserRole(roleId) {
|
|
@@ -1449,7 +3032,7 @@ var listEntries = async (req, res) => {
|
|
|
1449
3032
|
const page = Math.max(1, parseInt(String(req.query.page ?? 1)));
|
|
1450
3033
|
const limit = Math.min(100, Math.max(1, parseInt(String(req.query.limit ?? 20))));
|
|
1451
3034
|
const offset = (page - 1) * limit;
|
|
1452
|
-
const allowedSort = ["created_at", "updated_at", "published_at", ...ct.fields.map((
|
|
3035
|
+
const allowedSort = ["created_at", "updated_at", "published_at", ...ct.fields.map((f2) => f2.name)];
|
|
1453
3036
|
const sortField = allowedSort.includes(String(req.query.sort ?? "")) ? String(req.query.sort) : "created_at";
|
|
1454
3037
|
const sortDir = req.query.order === "asc" ? "ASC" : "DESC";
|
|
1455
3038
|
assertSafeIdentifier(sortField);
|
|
@@ -1475,7 +3058,7 @@ var listEntries = async (req, res) => {
|
|
|
1475
3058
|
if (!locale2)
|
|
1476
3059
|
return true;
|
|
1477
3060
|
const localized = row.localized && typeof row.localized === "object" ? row.localized : {};
|
|
1478
|
-
const locales = Object.keys(localized).filter((
|
|
3061
|
+
const locales = Object.keys(localized).filter((k3) => !k3.startsWith("_"));
|
|
1479
3062
|
const meta = localized._meta || {};
|
|
1480
3063
|
const enabled = meta.enabled ?? locales.length > 0;
|
|
1481
3064
|
const primary = meta.primary;
|
|
@@ -1484,7 +3067,7 @@ var listEntries = async (req, res) => {
|
|
|
1484
3067
|
}
|
|
1485
3068
|
return primary === locale2;
|
|
1486
3069
|
}
|
|
1487
|
-
const filtered = rows.filter((
|
|
3070
|
+
const filtered = rows.filter((r2) => entryMatchesLocale(r2, locale));
|
|
1488
3071
|
const data = await Promise.all(filtered.map(async (row) => {
|
|
1489
3072
|
const mmIds = await loadManyToManyIds(row.id, ct.tableName, ct.fields);
|
|
1490
3073
|
const resolved = resolveLocalizedRow(row, ct, locale, fallbacks);
|
|
@@ -1498,7 +3081,7 @@ var listEntries = async (req, res) => {
|
|
|
1498
3081
|
if (locale) {
|
|
1499
3082
|
try {
|
|
1500
3083
|
const { rows: allRows } = await pool_default.query(`SELECT localized FROM ${quotedTableName}`);
|
|
1501
|
-
const matching = allRows.filter((
|
|
3084
|
+
const matching = allRows.filter((r2) => entryMatchesLocale(r2, locale));
|
|
1502
3085
|
total = matching.length;
|
|
1503
3086
|
} catch (err) {
|
|
1504
3087
|
}
|
|
@@ -1506,14 +3089,14 @@ var listEntries = async (req, res) => {
|
|
|
1506
3089
|
res.json({ data, total, page, limit });
|
|
1507
3090
|
};
|
|
1508
3091
|
async function loadManyToManyIds(entryId, tableName, fields) {
|
|
1509
|
-
const mmFields = fields.filter((
|
|
3092
|
+
const mmFields = fields.filter((f2) => f2.type === "relation" && (f2.relationType ?? "many-to-one") === "many-to-many");
|
|
1510
3093
|
if (mmFields.length === 0)
|
|
1511
3094
|
return {};
|
|
1512
3095
|
const result = {};
|
|
1513
|
-
await Promise.all(mmFields.map(async (
|
|
1514
|
-
const jt = junctionTableName2(tableName,
|
|
3096
|
+
await Promise.all(mmFields.map(async (f2) => {
|
|
3097
|
+
const jt = junctionTableName2(tableName, f2.name);
|
|
1515
3098
|
const { rows } = await pool_default.query(`SELECT target_id FROM ${quoteIdentifier(jt)} WHERE source_id = $1`, [entryId]);
|
|
1516
|
-
result[
|
|
3099
|
+
result[f2.name] = rows.map((r2) => r2.target_id);
|
|
1517
3100
|
}));
|
|
1518
3101
|
return result;
|
|
1519
3102
|
}
|
|
@@ -1559,13 +3142,13 @@ var createEntry = async (req, res) => {
|
|
|
1559
3142
|
res.status(403).json({ error: "Single types are read-only for User role" });
|
|
1560
3143
|
return;
|
|
1561
3144
|
}
|
|
1562
|
-
const mmFields = ct.fields.filter((
|
|
1563
|
-
const fields = ct.fields.filter((
|
|
1564
|
-
fields.forEach((
|
|
3145
|
+
const mmFields = ct.fields.filter((f2) => f2.type === "relation" && (f2.relationType ?? "many-to-one") === "many-to-many" && req.body[f2.name] !== void 0);
|
|
3146
|
+
const fields = ct.fields.filter((f2) => req.body[f2.name] !== void 0 && !isVirtualRelation(f2));
|
|
3147
|
+
fields.forEach((f2) => assertSafeIdentifier(f2.name));
|
|
1565
3148
|
if (ct.kind === "single") {
|
|
1566
3149
|
const { rows: existing } = await pool_default.query(`SELECT id FROM ${quotedTableName} LIMIT 1`);
|
|
1567
3150
|
if (existing[0]) {
|
|
1568
|
-
const setClauses = fields.map((
|
|
3151
|
+
const setClauses = fields.map((f2, i2) => f2.type === "media-gallery" || f2.type === "array" || f2.type === "navigation" ? `${quoteIdentifier(f2.name)} = $${i2 + 1}::jsonb` : `${quoteIdentifier(f2.name)} = $${i2 + 1}`).join(", ");
|
|
1569
3152
|
const extraClauses = [];
|
|
1570
3153
|
const extraValues2 = [];
|
|
1571
3154
|
if (req.body.localized !== void 0) {
|
|
@@ -1574,10 +3157,10 @@ var createEntry = async (req, res) => {
|
|
|
1574
3157
|
}
|
|
1575
3158
|
const allClauses = [setClauses, ...extraClauses].filter(Boolean).join(", ");
|
|
1576
3159
|
const values2 = [
|
|
1577
|
-
...fields.map((
|
|
1578
|
-
const
|
|
1579
|
-
const normalized =
|
|
1580
|
-
return
|
|
3160
|
+
...fields.map((f2) => {
|
|
3161
|
+
const v3 = req.body[f2.name];
|
|
3162
|
+
const normalized = f2.type === "navigation" ? normalizeNavigationItems(v3) : v3;
|
|
3163
|
+
return f2.type === "media-gallery" || f2.type === "array" || f2.type === "navigation" ? JSON.stringify(normalized) : v3;
|
|
1581
3164
|
}),
|
|
1582
3165
|
...extraValues2,
|
|
1583
3166
|
existing[0].id
|
|
@@ -1585,9 +3168,9 @@ var createEntry = async (req, res) => {
|
|
|
1585
3168
|
const updateSql = fields.length + extraValues2.length > 0 ? `UPDATE ${quotedTableName} SET ${allClauses}, updated_at = NOW() WHERE id = $${fields.length + extraValues2.length + 1} RETURNING *` : `UPDATE ${quotedTableName} SET updated_at = NOW() WHERE id = $1 RETURNING *`;
|
|
1586
3169
|
const updateValues = fields.length + extraValues2.length > 0 ? values2 : [existing[0].id];
|
|
1587
3170
|
const { rows: rows2 } = await pool_default.query(updateSql, updateValues);
|
|
1588
|
-
await Promise.all(mmFields.map((
|
|
1589
|
-
const ids = Array.isArray(req.body[
|
|
1590
|
-
return syncManyToMany(existing[0].id, ct.tableName,
|
|
3171
|
+
await Promise.all(mmFields.map((f2) => {
|
|
3172
|
+
const ids = Array.isArray(req.body[f2.name]) ? req.body[f2.name] : [];
|
|
3173
|
+
return syncManyToMany(existing[0].id, ct.tableName, f2, ids);
|
|
1591
3174
|
}));
|
|
1592
3175
|
res.json(normalizeNavigationFields(rows2[0], ct.fields));
|
|
1593
3176
|
return;
|
|
@@ -1603,27 +3186,27 @@ var createEntry = async (req, res) => {
|
|
|
1603
3186
|
extraPlaceholders.push(`$${3 + fields.length}::jsonb`);
|
|
1604
3187
|
extraValues.push(JSON.stringify(req.body.localized));
|
|
1605
3188
|
}
|
|
1606
|
-
const cols = ["id", "created_by", ...fields.map((
|
|
3189
|
+
const cols = ["id", "created_by", ...fields.map((f2) => f2.name), ...extraCols].map((col) => quoteIdentifier(col)).join(", ");
|
|
1607
3190
|
const placeholders = [
|
|
1608
3191
|
"$1",
|
|
1609
3192
|
"$2",
|
|
1610
|
-
...fields.map((
|
|
3193
|
+
...fields.map((f2, i2) => f2.type === "media-gallery" || f2.type === "array" || f2.type === "navigation" ? `$${i2 + 3}::jsonb` : `$${i2 + 3}`),
|
|
1611
3194
|
...extraPlaceholders
|
|
1612
3195
|
].join(", ");
|
|
1613
3196
|
const values = [
|
|
1614
3197
|
id,
|
|
1615
3198
|
userId,
|
|
1616
|
-
...fields.map((
|
|
1617
|
-
const
|
|
1618
|
-
const normalized =
|
|
1619
|
-
return
|
|
3199
|
+
...fields.map((f2) => {
|
|
3200
|
+
const v3 = req.body[f2.name];
|
|
3201
|
+
const normalized = f2.type === "navigation" ? normalizeNavigationItems(v3) : v3;
|
|
3202
|
+
return f2.type === "media-gallery" || f2.type === "array" || f2.type === "navigation" ? JSON.stringify(normalized) : v3;
|
|
1620
3203
|
}),
|
|
1621
3204
|
...extraValues
|
|
1622
3205
|
];
|
|
1623
3206
|
const { rows } = await pool_default.query(`INSERT INTO ${quotedTableName} (${cols}) VALUES (${placeholders}) RETURNING *`, values);
|
|
1624
|
-
await Promise.all(mmFields.map((
|
|
1625
|
-
const ids = Array.isArray(req.body[
|
|
1626
|
-
return syncManyToMany(id, ct.tableName,
|
|
3207
|
+
await Promise.all(mmFields.map((f2) => {
|
|
3208
|
+
const ids = Array.isArray(req.body[f2.name]) ? req.body[f2.name] : [];
|
|
3209
|
+
return syncManyToMany(id, ct.tableName, f2, ids);
|
|
1627
3210
|
}));
|
|
1628
3211
|
res.status(201).json(normalizeNavigationFields(rows[0], ct.fields));
|
|
1629
3212
|
triggerWebhooks("entry.created", { content_type: req.params.slug, entry_id: rows[0].id });
|
|
@@ -1680,10 +3263,10 @@ var updateEntry = async (req, res) => {
|
|
|
1680
3263
|
return;
|
|
1681
3264
|
}
|
|
1682
3265
|
}
|
|
1683
|
-
const mmFields = ct.fields.filter((
|
|
1684
|
-
const fields = ct.fields.filter((
|
|
1685
|
-
fields.forEach((
|
|
1686
|
-
const setClauses = fields.map((
|
|
3266
|
+
const mmFields = ct.fields.filter((f2) => f2.type === "relation" && (f2.relationType ?? "many-to-one") === "many-to-many" && req.body[f2.name] !== void 0);
|
|
3267
|
+
const fields = ct.fields.filter((f2) => req.body[f2.name] !== void 0 && !isVirtualRelation(f2));
|
|
3268
|
+
fields.forEach((f2) => assertSafeIdentifier(f2.name));
|
|
3269
|
+
const setClauses = fields.map((f2, i2) => f2.type === "media-gallery" || f2.type === "array" || f2.type === "navigation" ? `${quoteIdentifier(f2.name)} = $${i2 + 1}::jsonb` : `${quoteIdentifier(f2.name)} = $${i2 + 1}`).join(", ");
|
|
1687
3270
|
const extraClauses = [];
|
|
1688
3271
|
const extraValues = [];
|
|
1689
3272
|
if (req.body.localized !== void 0) {
|
|
@@ -1692,10 +3275,10 @@ var updateEntry = async (req, res) => {
|
|
|
1692
3275
|
}
|
|
1693
3276
|
const allClauses = [setClauses, ...extraClauses].filter(Boolean).join(", ");
|
|
1694
3277
|
const values = [
|
|
1695
|
-
...fields.map((
|
|
1696
|
-
const
|
|
1697
|
-
const normalized =
|
|
1698
|
-
return
|
|
3278
|
+
...fields.map((f2) => {
|
|
3279
|
+
const v3 = req.body[f2.name];
|
|
3280
|
+
const normalized = f2.type === "navigation" ? normalizeNavigationItems(v3) : v3;
|
|
3281
|
+
return f2.type === "media-gallery" || f2.type === "array" || f2.type === "navigation" ? JSON.stringify(normalized) : v3;
|
|
1699
3282
|
}),
|
|
1700
3283
|
...extraValues,
|
|
1701
3284
|
req.params.id
|
|
@@ -1707,9 +3290,9 @@ var updateEntry = async (req, res) => {
|
|
|
1707
3290
|
res.status(404).json({ error: "Entry not found" });
|
|
1708
3291
|
return;
|
|
1709
3292
|
}
|
|
1710
|
-
await Promise.all(mmFields.map((
|
|
1711
|
-
const ids = Array.isArray(req.body[
|
|
1712
|
-
return syncManyToMany(req.params.id, ct.tableName,
|
|
3293
|
+
await Promise.all(mmFields.map((f2) => {
|
|
3294
|
+
const ids = Array.isArray(req.body[f2.name]) ? req.body[f2.name] : [];
|
|
3295
|
+
return syncManyToMany(req.params.id, ct.tableName, f2, ids);
|
|
1713
3296
|
}));
|
|
1714
3297
|
res.json(normalizeNavigationFields(rows[0], ct.fields));
|
|
1715
3298
|
triggerWebhooks("entry.updated", { content_type: req.params.slug, entry_id: req.params.id });
|
|
@@ -1873,6 +3456,13 @@ var UpdateMeSchema = z4.object({
|
|
|
1873
3456
|
organization: z4.string().max(150).optional(),
|
|
1874
3457
|
country: z4.string().max(100).optional()
|
|
1875
3458
|
});
|
|
3459
|
+
var TwoFactorCodeSchema = z4.object({
|
|
3460
|
+
code: z4.string().trim().length(6)
|
|
3461
|
+
});
|
|
3462
|
+
var DisableTwoFactorSchema = z4.object({
|
|
3463
|
+
password: z4.string().min(1),
|
|
3464
|
+
code: z4.string().trim().length(6)
|
|
3465
|
+
});
|
|
1876
3466
|
async function resolveAvatarUrl(row) {
|
|
1877
3467
|
if (!row.avatar_url || row.avatar_url.startsWith("http"))
|
|
1878
3468
|
return row;
|
|
@@ -1892,7 +3482,7 @@ async function listUsers(_req, res) {
|
|
|
1892
3482
|
}
|
|
1893
3483
|
async function getMe(req, res) {
|
|
1894
3484
|
const { rows } = await pool_default.query(`SELECT u.id, u.email, u.role_id, u.first_name, u.last_name, u.avatar_url,
|
|
1895
|
-
u.job_title, u.organization, u.country, u.created_at,
|
|
3485
|
+
u.job_title, u.organization, u.country, u.two_factor_enabled, u.created_at,
|
|
1896
3486
|
r.permissions
|
|
1897
3487
|
FROM plank_users u
|
|
1898
3488
|
JOIN plank_roles r ON r.id = u.role_id
|
|
@@ -1902,12 +3492,100 @@ async function getMe(req, res) {
|
|
|
1902
3492
|
return;
|
|
1903
3493
|
}
|
|
1904
3494
|
const resolved = await resolveAvatarUrl(rows[0]);
|
|
1905
|
-
res.json({ ...resolved, permissions: rows[0].permissions });
|
|
3495
|
+
res.json({ ...resolved, permissions: rows[0].permissions, two_factor_enabled: rows[0].two_factor_enabled });
|
|
3496
|
+
}
|
|
3497
|
+
async function getTwoFactorStatus(req, res) {
|
|
3498
|
+
const { rows } = await pool_default.query("SELECT two_factor_enabled FROM plank_users WHERE id = $1", [req.user.id]);
|
|
3499
|
+
if (!rows[0]) {
|
|
3500
|
+
res.status(404).json({ error: "User not found" });
|
|
3501
|
+
return;
|
|
3502
|
+
}
|
|
3503
|
+
res.json({ enabled: rows[0].two_factor_enabled });
|
|
3504
|
+
}
|
|
3505
|
+
async function startTwoFactorSetup(req, res) {
|
|
3506
|
+
const { rows } = await pool_default.query("SELECT email, two_factor_enabled FROM plank_users WHERE id = $1", [req.user.id]);
|
|
3507
|
+
if (!rows[0]) {
|
|
3508
|
+
res.status(404).json({ error: "User not found" });
|
|
3509
|
+
return;
|
|
3510
|
+
}
|
|
3511
|
+
if (rows[0].two_factor_enabled) {
|
|
3512
|
+
res.status(400).json({ error: "2FA is already enabled" });
|
|
3513
|
+
return;
|
|
3514
|
+
}
|
|
3515
|
+
const secret = I2();
|
|
3516
|
+
await pool_default.query("UPDATE plank_users SET two_factor_temp_secret = $1 WHERE id = $2", [
|
|
3517
|
+
encrypt(secret),
|
|
3518
|
+
req.user.id
|
|
3519
|
+
]);
|
|
3520
|
+
const otpauthUri = T2({ issuer: "Plank CMS", label: rows[0].email, secret });
|
|
3521
|
+
res.json({ otpauthUri, secret });
|
|
3522
|
+
}
|
|
3523
|
+
async function verifyTwoFactorSetup(req, res) {
|
|
3524
|
+
const parsed = TwoFactorCodeSchema.safeParse(req.body);
|
|
3525
|
+
if (!parsed.success) {
|
|
3526
|
+
res.status(400).json({ errors: flattenError4(parsed.error, (i2) => i2.message) });
|
|
3527
|
+
return;
|
|
3528
|
+
}
|
|
3529
|
+
const { rows } = await pool_default.query("SELECT two_factor_temp_secret FROM plank_users WHERE id = $1", [req.user.id]);
|
|
3530
|
+
const tempSecret = rows[0]?.two_factor_temp_secret;
|
|
3531
|
+
if (!tempSecret) {
|
|
3532
|
+
res.status(400).json({ error: "No pending 2FA setup found" });
|
|
3533
|
+
return;
|
|
3534
|
+
}
|
|
3535
|
+
const result = d3({ token: parsed.data.code, secret: decrypt(tempSecret) });
|
|
3536
|
+
if (!result.valid) {
|
|
3537
|
+
res.status(401).json({ error: "Invalid verification code" });
|
|
3538
|
+
return;
|
|
3539
|
+
}
|
|
3540
|
+
await pool_default.query(`UPDATE plank_users
|
|
3541
|
+
SET two_factor_enabled = TRUE,
|
|
3542
|
+
two_factor_secret = two_factor_temp_secret,
|
|
3543
|
+
two_factor_temp_secret = NULL,
|
|
3544
|
+
session_version = session_version + 1
|
|
3545
|
+
WHERE id = $1`, [req.user.id]);
|
|
3546
|
+
res.status(204).end();
|
|
3547
|
+
}
|
|
3548
|
+
async function disableTwoFactor(req, res) {
|
|
3549
|
+
const parsed = DisableTwoFactorSchema.safeParse(req.body);
|
|
3550
|
+
if (!parsed.success) {
|
|
3551
|
+
res.status(400).json({ errors: flattenError4(parsed.error, (i2) => i2.message) });
|
|
3552
|
+
return;
|
|
3553
|
+
}
|
|
3554
|
+
const { rows } = await pool_default.query("SELECT two_factor_enabled, two_factor_secret, password FROM plank_users WHERE id = $1", [req.user.id]);
|
|
3555
|
+
const user = rows[0];
|
|
3556
|
+
if (!user) {
|
|
3557
|
+
res.status(404).json({ error: "User not found" });
|
|
3558
|
+
return;
|
|
3559
|
+
}
|
|
3560
|
+
if (!user.two_factor_enabled || !user.two_factor_secret) {
|
|
3561
|
+
res.status(400).json({ error: "2FA is not enabled" });
|
|
3562
|
+
return;
|
|
3563
|
+
}
|
|
3564
|
+
const passwordOk = await bcrypt2.compare(parsed.data.password, user.password);
|
|
3565
|
+
if (!passwordOk) {
|
|
3566
|
+
res.status(401).json({ error: "Current password is incorrect" });
|
|
3567
|
+
return;
|
|
3568
|
+
}
|
|
3569
|
+
const result = d3({
|
|
3570
|
+
token: parsed.data.code,
|
|
3571
|
+
secret: decrypt(user.two_factor_secret)
|
|
3572
|
+
});
|
|
3573
|
+
if (!result.valid) {
|
|
3574
|
+
res.status(401).json({ error: "Invalid verification code" });
|
|
3575
|
+
return;
|
|
3576
|
+
}
|
|
3577
|
+
await pool_default.query(`UPDATE plank_users
|
|
3578
|
+
SET two_factor_enabled = FALSE,
|
|
3579
|
+
two_factor_secret = NULL,
|
|
3580
|
+
two_factor_temp_secret = NULL,
|
|
3581
|
+
session_version = session_version + 1
|
|
3582
|
+
WHERE id = $1`, [req.user.id]);
|
|
3583
|
+
res.status(204).end();
|
|
1906
3584
|
}
|
|
1907
3585
|
async function updateMe(req, res) {
|
|
1908
3586
|
const parsed = UpdateMeSchema.safeParse(req.body);
|
|
1909
3587
|
if (!parsed.success) {
|
|
1910
|
-
res.status(400).json({ errors: flattenError4(parsed.error, (
|
|
3588
|
+
res.status(400).json({ errors: flattenError4(parsed.error, (i2) => i2.message) });
|
|
1911
3589
|
return;
|
|
1912
3590
|
}
|
|
1913
3591
|
const { firstName, lastName, jobTitle, organization, country } = parsed.data;
|
|
@@ -1978,7 +3656,7 @@ async function deleteAvatar(req, res) {
|
|
|
1978
3656
|
async function changePassword(req, res) {
|
|
1979
3657
|
const parsed = ChangePasswordSchema.safeParse(req.body);
|
|
1980
3658
|
if (!parsed.success) {
|
|
1981
|
-
res.status(400).json({ errors: flattenError4(parsed.error, (
|
|
3659
|
+
res.status(400).json({ errors: flattenError4(parsed.error, (i2) => i2.message) });
|
|
1982
3660
|
return;
|
|
1983
3661
|
}
|
|
1984
3662
|
const { rows } = await pool_default.query("SELECT password FROM plank_users WHERE id = $1", [req.user.id]);
|
|
@@ -1992,13 +3670,13 @@ async function changePassword(req, res) {
|
|
|
1992
3670
|
return;
|
|
1993
3671
|
}
|
|
1994
3672
|
const hashed = await bcrypt2.hash(parsed.data.newPassword, 12);
|
|
1995
|
-
await pool_default.query("UPDATE plank_users SET password = $1 WHERE id = $2", [hashed, req.user.id]);
|
|
3673
|
+
await pool_default.query("UPDATE plank_users SET password = $1, session_version = session_version + 1 WHERE id = $2", [hashed, req.user.id]);
|
|
1996
3674
|
res.status(204).end();
|
|
1997
3675
|
}
|
|
1998
3676
|
async function createUser(req, res) {
|
|
1999
3677
|
const parsed = CreateUserSchema.safeParse(req.body);
|
|
2000
3678
|
if (!parsed.success) {
|
|
2001
|
-
res.status(400).json({ errors: flattenError4(parsed.error, (
|
|
3679
|
+
res.status(400).json({ errors: flattenError4(parsed.error, (i2) => i2.message) });
|
|
2002
3680
|
return;
|
|
2003
3681
|
}
|
|
2004
3682
|
const { email, password, roleId } = parsed.data;
|
|
@@ -2016,7 +3694,7 @@ async function createUser(req, res) {
|
|
|
2016
3694
|
async function updateUser(req, res) {
|
|
2017
3695
|
const parsed = UpdateUserSchema.safeParse(req.body);
|
|
2018
3696
|
if (!parsed.success) {
|
|
2019
|
-
res.status(400).json({ errors: flattenError4(parsed.error, (
|
|
3697
|
+
res.status(400).json({ errors: flattenError4(parsed.error, (i2) => i2.message) });
|
|
2020
3698
|
return;
|
|
2021
3699
|
}
|
|
2022
3700
|
const { email, roleId, firstName, lastName } = parsed.data;
|
|
@@ -2124,7 +3802,7 @@ async function resetRoles(_req, res) {
|
|
|
2124
3802
|
}
|
|
2125
3803
|
|
|
2126
3804
|
// ../core/dist/controllers/apiTokens.js
|
|
2127
|
-
import { randomBytes as
|
|
3805
|
+
import { randomBytes as randomBytes6, createHash } from "crypto";
|
|
2128
3806
|
import { z as z7, flattenError as flattenError5 } from "zod";
|
|
2129
3807
|
var CreateTokenSchema = z7.object({
|
|
2130
3808
|
name: z7.string().min(1),
|
|
@@ -2140,12 +3818,12 @@ async function listApiTokens(_req, res) {
|
|
|
2140
3818
|
async function createApiToken(req, res) {
|
|
2141
3819
|
const parsed = CreateTokenSchema.safeParse(req.body);
|
|
2142
3820
|
if (!parsed.success) {
|
|
2143
|
-
res.status(400).json({ errors: flattenError5(parsed.error, (
|
|
3821
|
+
res.status(400).json({ errors: flattenError5(parsed.error, (i2) => i2.message) });
|
|
2144
3822
|
return;
|
|
2145
3823
|
}
|
|
2146
3824
|
const { name, accessType } = parsed.data;
|
|
2147
3825
|
const id = createId();
|
|
2148
|
-
const token = `plank_${
|
|
3826
|
+
const token = `plank_${randomBytes6(32).toString("hex")}`;
|
|
2149
3827
|
const hashed = hashToken(token);
|
|
2150
3828
|
await pool_default.query("INSERT INTO plank_api_tokens (id, name, token, access_type, created_by) VALUES ($1, $2, $3, $4, $5)", [id, name, hashed, accessType, req.user.id]);
|
|
2151
3829
|
res.status(201).json({ id, name, accessType, token });
|
|
@@ -2160,7 +3838,7 @@ async function deleteApiToken(req, res) {
|
|
|
2160
3838
|
}
|
|
2161
3839
|
|
|
2162
3840
|
// ../core/dist/controllers/media.js
|
|
2163
|
-
import { randomBytes as
|
|
3841
|
+
import { randomBytes as randomBytes7 } from "crypto";
|
|
2164
3842
|
var MEDIA_PREFIX = "media";
|
|
2165
3843
|
async function listMedia(req, res) {
|
|
2166
3844
|
const page = Math.max(1, parseInt(req.query.page) || 1);
|
|
@@ -2173,18 +3851,18 @@ async function listMedia(req, res) {
|
|
|
2173
3851
|
ORDER BY created_at DESC
|
|
2174
3852
|
LIMIT $1 OFFSET $2`, [limit, offset, folderId]);
|
|
2175
3853
|
const provider = await getProvider();
|
|
2176
|
-
const items = await Promise.all(rows.map(async (
|
|
2177
|
-
id:
|
|
2178
|
-
filename:
|
|
2179
|
-
url: await provider.getUrl(
|
|
2180
|
-
mime_type:
|
|
2181
|
-
size:
|
|
2182
|
-
alt:
|
|
2183
|
-
width:
|
|
2184
|
-
height:
|
|
2185
|
-
folder_id:
|
|
2186
|
-
uploaded_by:
|
|
2187
|
-
created_at:
|
|
3854
|
+
const items = await Promise.all(rows.map(async (r2) => ({
|
|
3855
|
+
id: r2.id,
|
|
3856
|
+
filename: r2.filename,
|
|
3857
|
+
url: await provider.getUrl(r2.provider_key),
|
|
3858
|
+
mime_type: r2.mime_type,
|
|
3859
|
+
size: r2.size,
|
|
3860
|
+
alt: r2.alt,
|
|
3861
|
+
width: r2.width,
|
|
3862
|
+
height: r2.height,
|
|
3863
|
+
folder_id: r2.folder_id,
|
|
3864
|
+
uploaded_by: r2.uploaded_by,
|
|
3865
|
+
created_at: r2.created_at
|
|
2188
3866
|
})));
|
|
2189
3867
|
const total = rows[0] ? parseInt(rows[0].total) : 0;
|
|
2190
3868
|
res.json({ items, total, page, limit, pages: Math.ceil(total / limit) });
|
|
@@ -2206,12 +3884,12 @@ async function uploadMedia(req, res) {
|
|
|
2206
3884
|
}
|
|
2207
3885
|
}
|
|
2208
3886
|
if (isBundle) {
|
|
2209
|
-
const m3u8File = files.find((
|
|
3887
|
+
const m3u8File = files.find((f2) => f2.originalname.endsWith(".m3u8"));
|
|
2210
3888
|
if (!m3u8File) {
|
|
2211
3889
|
res.status(400).json({ error: "No .m3u8 file found in bundle" });
|
|
2212
3890
|
return;
|
|
2213
3891
|
}
|
|
2214
|
-
const bundleId =
|
|
3892
|
+
const bundleId = randomBytes7(8).toString("hex");
|
|
2215
3893
|
const prefix = [MEDIA_PREFIX, folderId, bundleId].filter(Boolean).join("/");
|
|
2216
3894
|
const rootDir = m3u8File.originalname.includes("/") ? m3u8File.originalname.split("/")[0] : null;
|
|
2217
3895
|
const stripRoot = (path) => rootDir && path.startsWith(`${rootDir}/`) ? path.slice(rootDir.length + 1) : path;
|
|
@@ -2385,7 +4063,7 @@ function maskSettings(namespace, settings) {
|
|
|
2385
4063
|
const sensitive = SENSITIVE_FIELDS2[namespace];
|
|
2386
4064
|
if (!sensitive)
|
|
2387
4065
|
return settings;
|
|
2388
|
-
return Object.fromEntries(Object.entries(settings).map(([
|
|
4066
|
+
return Object.fromEntries(Object.entries(settings).map(([k3, v3]) => [k3, sensitive.has(k3) && v3 ? MASKED : v3]));
|
|
2389
4067
|
}
|
|
2390
4068
|
async function getNamespaceSettings(req, res) {
|
|
2391
4069
|
const { namespace } = req.params;
|
|
@@ -2436,6 +4114,10 @@ router2.post("/users/me/avatar/confirm", confirmAvatar);
|
|
|
2436
4114
|
router2.delete("/users/me/avatar", deleteAvatar);
|
|
2437
4115
|
router2.get("/users/me/prefs/:key", getUserPref);
|
|
2438
4116
|
router2.put("/users/me/prefs/:key", setUserPref);
|
|
4117
|
+
router2.get("/users/me/2fa", getTwoFactorStatus);
|
|
4118
|
+
router2.post("/users/me/2fa/setup", startTwoFactorSetup);
|
|
4119
|
+
router2.post("/users/me/2fa/verify", verifyTwoFactorSetup);
|
|
4120
|
+
router2.post("/users/me/2fa/disable", disableTwoFactor);
|
|
2439
4121
|
router2.get("/roles", authorize("settings:users:read"), listRoles);
|
|
2440
4122
|
router2.put("/roles/:id", authorize("settings:roles:write"), updateRole);
|
|
2441
4123
|
router2.post("/roles/reset", authorize("settings:roles:write"), resetRoles);
|
|
@@ -2519,8 +4201,8 @@ function normalizeNavigationItems2(value) {
|
|
|
2519
4201
|
});
|
|
2520
4202
|
}
|
|
2521
4203
|
async function resolveMediaFields(entries, ct) {
|
|
2522
|
-
const singleFields = ct.fields.filter((
|
|
2523
|
-
const galleryFields = ct.fields.filter((
|
|
4204
|
+
const singleFields = ct.fields.filter((f2) => f2.type === "media").map((f2) => f2.name);
|
|
4205
|
+
const galleryFields = ct.fields.filter((f2) => f2.type === "media-gallery").map((f2) => f2.name);
|
|
2524
4206
|
if (singleFields.length === 0 && galleryFields.length === 0)
|
|
2525
4207
|
return;
|
|
2526
4208
|
const idSet = /* @__PURE__ */ new Set();
|
|
@@ -2545,8 +4227,8 @@ async function resolveMediaFields(entries, ct) {
|
|
|
2545
4227
|
const { rows } = await pool_default.query("SELECT id, provider_key FROM plank_media WHERE id = ANY($1)", [[...idSet]]);
|
|
2546
4228
|
const provider = await getProvider();
|
|
2547
4229
|
const urlMap = /* @__PURE__ */ new Map();
|
|
2548
|
-
await Promise.all(rows.map(async (
|
|
2549
|
-
urlMap.set(
|
|
4230
|
+
await Promise.all(rows.map(async (r2) => {
|
|
4231
|
+
urlMap.set(r2.id, await provider.getUrl(r2.provider_key));
|
|
2550
4232
|
}));
|
|
2551
4233
|
for (const entry of entries) {
|
|
2552
4234
|
for (const name of singleFields) {
|
|
@@ -2572,11 +4254,11 @@ var SYSTEM_FIELDS = /* @__PURE__ */ new Set([
|
|
|
2572
4254
|
"updated_at"
|
|
2573
4255
|
]);
|
|
2574
4256
|
function stripSystemFields(row) {
|
|
2575
|
-
return Object.fromEntries(Object.entries(row).filter(([
|
|
4257
|
+
return Object.fromEntries(Object.entries(row).filter(([k3]) => !SYSTEM_FIELDS.has(k3)));
|
|
2576
4258
|
}
|
|
2577
4259
|
async function resolveRelationFields(entries, ct) {
|
|
2578
|
-
const scalarFields = ct.fields.filter((
|
|
2579
|
-
const mmFields = ct.fields.filter((
|
|
4260
|
+
const scalarFields = ct.fields.filter((f2) => f2.type === "relation" && (f2.relationType === "many-to-one" || f2.relationType === "one-to-one" || !f2.relationType) && f2.relatedTable);
|
|
4261
|
+
const mmFields = ct.fields.filter((f2) => f2.type === "relation" && (f2.relationType ?? "many-to-one") === "many-to-many" && f2.relatedTable);
|
|
2580
4262
|
const entryIds = entries.map((e) => e.id);
|
|
2581
4263
|
await Promise.all([
|
|
2582
4264
|
...scalarFields.map(async (field) => {
|
|
@@ -2587,7 +4269,7 @@ async function resolveRelationFields(entries, ct) {
|
|
|
2587
4269
|
const { rows } = await pool_default.query(`SELECT * FROM ${field.relatedTable} WHERE id = ANY($1)`, [
|
|
2588
4270
|
ids
|
|
2589
4271
|
]);
|
|
2590
|
-
const map = new Map(rows.map((
|
|
4272
|
+
const map = new Map(rows.map((r2) => [r2.id, stripSystemFields(r2)]));
|
|
2591
4273
|
for (const entry of entries) {
|
|
2592
4274
|
const id = entry[field.name];
|
|
2593
4275
|
entry[field.name] = id ? map.get(id) ?? null : null;
|
|
@@ -2598,7 +4280,7 @@ async function resolveRelationFields(entries, ct) {
|
|
|
2598
4280
|
return;
|
|
2599
4281
|
const jt = `_rel_${ct.tableName}_${field.name}`;
|
|
2600
4282
|
const { rows: jRows } = await pool_default.query(`SELECT source_id, target_id FROM ${jt} WHERE source_id = ANY($1)`, [entryIds]);
|
|
2601
|
-
const allTargetIds = [...new Set(jRows.map((
|
|
4283
|
+
const allTargetIds = [...new Set(jRows.map((r2) => r2.target_id))];
|
|
2602
4284
|
const relatedMap = /* @__PURE__ */ new Map();
|
|
2603
4285
|
if (allTargetIds.length > 0) {
|
|
2604
4286
|
assertSafeIdentifier(field.relatedTable);
|
|
@@ -2639,22 +4321,22 @@ function serializeEntry(row, ct, statusParam, locale, fallbacks = []) {
|
|
|
2639
4321
|
if (locale) {
|
|
2640
4322
|
const localizedContainer = source && typeof source === "object" && source.localized && typeof source.localized === "object" ? source.localized : row.localized && typeof row.localized === "object" ? row.localized : {};
|
|
2641
4323
|
const localizableTypes = /* @__PURE__ */ new Set(["string", "text", "richtext", "uid"]);
|
|
2642
|
-
for (const
|
|
2643
|
-
if (!localizableTypes.has(
|
|
4324
|
+
for (const f2 of ct.fields) {
|
|
4325
|
+
if (!localizableTypes.has(f2.type))
|
|
2644
4326
|
continue;
|
|
2645
4327
|
let val = void 0;
|
|
2646
|
-
if (localizedContainer[locale] && localizedContainer[locale][
|
|
2647
|
-
val = localizedContainer[locale][
|
|
4328
|
+
if (localizedContainer[locale] && localizedContainer[locale][f2.name] !== void 0) {
|
|
4329
|
+
val = localizedContainer[locale][f2.name];
|
|
2648
4330
|
} else {
|
|
2649
4331
|
for (const fb of fallbacks) {
|
|
2650
|
-
if (localizedContainer[fb] && localizedContainer[fb][
|
|
2651
|
-
val = localizedContainer[fb][
|
|
4332
|
+
if (localizedContainer[fb] && localizedContainer[fb][f2.name] !== void 0) {
|
|
4333
|
+
val = localizedContainer[fb][f2.name];
|
|
2652
4334
|
break;
|
|
2653
4335
|
}
|
|
2654
4336
|
}
|
|
2655
4337
|
}
|
|
2656
4338
|
if (val !== void 0)
|
|
2657
|
-
effective[
|
|
4339
|
+
effective[f2.name] = val;
|
|
2658
4340
|
}
|
|
2659
4341
|
}
|
|
2660
4342
|
const out = { id: row.id };
|
|
@@ -2712,7 +4394,7 @@ var listPublicEntries = async (req, res) => {
|
|
|
2712
4394
|
const offset = (page - 1) * limit;
|
|
2713
4395
|
const locale = req.query.locale ? String(req.query.locale) : void 0;
|
|
2714
4396
|
const fallbacks = req.query.fallback ? String(req.query.fallback).split(",") : [];
|
|
2715
|
-
const knownFields = new Set(ct.fields.map((
|
|
4397
|
+
const knownFields = new Set(ct.fields.map((f2) => f2.name));
|
|
2716
4398
|
const systemSortFields = /* @__PURE__ */ new Set(["created_at", "updated_at", "published_at"]);
|
|
2717
4399
|
const filterClauses = [];
|
|
2718
4400
|
const filterValues = [];
|
|
@@ -2800,7 +4482,7 @@ function errorHandler(err, _req, res, _next) {
|
|
|
2800
4482
|
return;
|
|
2801
4483
|
}
|
|
2802
4484
|
if (err instanceof ZodError) {
|
|
2803
|
-
res.status(400).json({ errors: flattenError6(err, (
|
|
4485
|
+
res.status(400).json({ errors: flattenError6(err, (i2) => i2.message) });
|
|
2804
4486
|
return;
|
|
2805
4487
|
}
|
|
2806
4488
|
console.error("[plank] Unhandled error:", err);
|
|
@@ -2808,6 +4490,17 @@ function errorHandler(err, _req, res, _next) {
|
|
|
2808
4490
|
}
|
|
2809
4491
|
|
|
2810
4492
|
// ../core/dist/app.js
|
|
4493
|
+
function assertSecurityEnv() {
|
|
4494
|
+
if (process.env.NODE_ENV !== "production")
|
|
4495
|
+
return;
|
|
4496
|
+
if (!process.env.PLANK_JWT_SECRET || process.env.PLANK_JWT_SECRET.length < 32) {
|
|
4497
|
+
throw new Error("PLANK_JWT_SECRET is required in production and should be at least 32 characters.");
|
|
4498
|
+
}
|
|
4499
|
+
if (!process.env.PLANK_ENCRYPTION_KEY || process.env.PLANK_ENCRYPTION_KEY.length !== 64) {
|
|
4500
|
+
throw new Error("PLANK_ENCRYPTION_KEY is required in production and must be 64 hex characters.");
|
|
4501
|
+
}
|
|
4502
|
+
}
|
|
4503
|
+
assertSecurityEnv();
|
|
2811
4504
|
var app = express();
|
|
2812
4505
|
app.use(helmet({
|
|
2813
4506
|
contentSecurityPolicy: {
|
|
@@ -2826,9 +4519,9 @@ app.use("/cms/auth", cmsCorOptions, auth_default);
|
|
|
2826
4519
|
app.use("/cms/admin", cmsCorOptions, admin_default);
|
|
2827
4520
|
app.use("/api", cors(), public_default);
|
|
2828
4521
|
app.get("/", (_req, res) => res.redirect("/admin"));
|
|
2829
|
-
var adminDist = process.env.PLANK_ADMIN_DIST ??
|
|
4522
|
+
var adminDist = process.env.PLANK_ADMIN_DIST ?? join4(dirname2(fileURLToPath2(import.meta.url)), "../public/admin");
|
|
2830
4523
|
app.use("/admin", express.static(adminDist));
|
|
2831
|
-
app.get("/admin/*path", (_req, res) => res.sendFile(
|
|
4524
|
+
app.get("/admin/*path", (_req, res) => res.sendFile(join4(adminDist, "index.html")));
|
|
2832
4525
|
app.use(errorHandler);
|
|
2833
4526
|
var app_default = app;
|
|
2834
4527
|
|
|
@@ -2847,3 +4540,8 @@ async function start() {
|
|
|
2847
4540
|
export {
|
|
2848
4541
|
start
|
|
2849
4542
|
};
|
|
4543
|
+
/*! Bundled license information:
|
|
4544
|
+
|
|
4545
|
+
@scure/base/index.js:
|
|
4546
|
+
(*! scure-base - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
|
|
4547
|
+
*/
|