@spfn/auth 0.2.0-beta.90 → 0.2.0-beta.91
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -0
- package/dist/{authenticate-CnccboAg.d.ts → authenticate-DlTGaBT8.d.ts} +26 -6
- package/dist/client-proof.d.ts +47 -118
- package/dist/client-proof.js +46 -18
- package/dist/client-proof.js.map +1 -1
- package/dist/errors.d.ts +1 -1
- package/dist/index.d.ts +7 -7
- package/dist/nextjs/server.d.ts +2 -2
- package/dist/server.d.ts +204 -84
- package/dist/server.js +473 -133
- package/dist/server.js.map +1 -1
- package/dist/{session-CFK4BT25.d.ts → session-DTHahDQ9.d.ts} +1 -1
- package/dist/{types-CD95yudz.d.ts → types-DYyhze28.d.ts} +1 -1
- package/dist/wire-version-CtzMKvBB.d.ts +134 -0
- package/migrations/20260805143152_vengeful_ravenous/migration.sql +4 -0
- package/migrations/20260805143152_vengeful_ravenous/snapshot.json +3190 -0
- package/package.json +2 -2
package/dist/server.js
CHANGED
|
@@ -1735,8 +1735,8 @@ function RequiredKeys(properties) {
|
|
|
1735
1735
|
return keys;
|
|
1736
1736
|
}
|
|
1737
1737
|
function _Object(properties, options) {
|
|
1738
|
-
const
|
|
1739
|
-
const schematic =
|
|
1738
|
+
const required2 = RequiredKeys(properties);
|
|
1739
|
+
const schematic = required2.length > 0 ? { [Kind]: "Object", type: "object", properties, required: required2 } : { [Kind]: "Object", type: "object", properties };
|
|
1740
1740
|
return CreateType(schematic, options);
|
|
1741
1741
|
}
|
|
1742
1742
|
var Object2;
|
|
@@ -4725,6 +4725,19 @@ var init_user_profiles = __esm({
|
|
|
4725
4725
|
}
|
|
4726
4726
|
});
|
|
4727
4727
|
|
|
4728
|
+
// src/server/client-proof/wire-headers.ts
|
|
4729
|
+
var SERVER_CONTRACT_HEADERS, CLIENT_KINDS;
|
|
4730
|
+
var init_wire_headers = __esm({
|
|
4731
|
+
"src/server/client-proof/wire-headers.ts"() {
|
|
4732
|
+
"use strict";
|
|
4733
|
+
SERVER_CONTRACT_HEADERS = {
|
|
4734
|
+
version: "x-spfn-server-contract-version",
|
|
4735
|
+
supportedRange: "x-spfn-supported-contract-range"
|
|
4736
|
+
};
|
|
4737
|
+
CLIENT_KINDS = ["web", "ios", "android"];
|
|
4738
|
+
}
|
|
4739
|
+
});
|
|
4740
|
+
|
|
4728
4741
|
// src/server/entities/user-public-keys.ts
|
|
4729
4742
|
import { text as text4, boolean as boolean3, index as index4 } from "drizzle-orm/pg-core";
|
|
4730
4743
|
import { id as id4, foreignKey as foreignKey3, enumText as enumText2, utcTimestamp as utcTimestamp2 } from "@spfn/core/db";
|
|
@@ -4733,6 +4746,7 @@ var init_user_public_keys = __esm({
|
|
|
4733
4746
|
"src/server/entities/user-public-keys.ts"() {
|
|
4734
4747
|
"use strict";
|
|
4735
4748
|
init_types();
|
|
4749
|
+
init_wire_headers();
|
|
4736
4750
|
init_users();
|
|
4737
4751
|
init_schema4();
|
|
4738
4752
|
userPublicKeys = authSchema.table(
|
|
@@ -4771,6 +4785,26 @@ var init_user_public_keys = __esm({
|
|
|
4771
4785
|
// null: the client sent none
|
|
4772
4786
|
// Used for: the same list, alongside deviceName
|
|
4773
4787
|
platform: enumText2("platform", KEY_PLATFORM),
|
|
4788
|
+
// What the client said about itself on the last request signed by this key.
|
|
4789
|
+
//
|
|
4790
|
+
// The three come from x-spfn-client-kind, x-spfn-client-version and
|
|
4791
|
+
// x-spfn-client-contract-version. They are client-supplied and
|
|
4792
|
+
// unauthenticated, exactly like deviceName above: nothing is authorized by
|
|
4793
|
+
// them, and a client that lies about its version gains nothing but a wrong
|
|
4794
|
+
// entry in its owner's own device list.
|
|
4795
|
+
//
|
|
4796
|
+
// They exist so the server knows which release each deployed client runs.
|
|
4797
|
+
// Refusing an outdated client is the last resort; reaching its owner first
|
|
4798
|
+
// needs a list of who runs what, and announcing a version is not the same
|
|
4799
|
+
// as the server having recorded it.
|
|
4800
|
+
clientKind: enumText2("client_kind", CLIENT_KINDS),
|
|
4801
|
+
clientVersion: text4("client_version"),
|
|
4802
|
+
clientContractVersion: text4("client_contract_version"),
|
|
4803
|
+
// When any of the three above last changed — an app update, in practice.
|
|
4804
|
+
// Not when they were last seen: a value that moves on every request is a
|
|
4805
|
+
// write on every request, and the question this answers is "since when has
|
|
4806
|
+
// this device been on this release", which only a change can answer.
|
|
4807
|
+
clientSeenAt: utcTimestamp2("client_seen_at"),
|
|
4774
4808
|
// Key status
|
|
4775
4809
|
// false: Key is deactivated (cannot be used for verification)
|
|
4776
4810
|
// Used for: soft key rotation, temporary key suspension
|
|
@@ -5697,7 +5731,7 @@ var init_users_repository = __esm({
|
|
|
5697
5731
|
|
|
5698
5732
|
// src/server/repositories/keys.repository.ts
|
|
5699
5733
|
import { BaseRepository as BaseRepository2 } from "@spfn/core/db";
|
|
5700
|
-
import { eq as eq2, and as and2, or, isNull, lt, ne, desc } from "drizzle-orm";
|
|
5734
|
+
import { eq as eq2, and as and2, or, isNull, lt, ne, desc, sql as sql3 } from "drizzle-orm";
|
|
5701
5735
|
var LAST_USED_THROTTLE_MS, KeysRepository, keysRepository;
|
|
5702
5736
|
var init_keys_repository = __esm({
|
|
5703
5737
|
"src/server/repositories/keys.repository.ts"() {
|
|
@@ -5916,17 +5950,44 @@ var init_keys_repository = __esm({
|
|
|
5916
5950
|
* LAST_USED_THROTTLE_MS), so a busy key isn't UPDATEd on every request. The
|
|
5917
5951
|
* throttle lives in the WHERE clause — atomic, no read-then-write race. No
|
|
5918
5952
|
* RETURNING (callers fire-and-forget and discard the row).
|
|
5953
|
+
*
|
|
5954
|
+
* `identity` is what the client said about itself on this request. It is
|
|
5955
|
+
* recorded on the same row, and the throttle does not apply to it: a version
|
|
5956
|
+
* that changed is written immediately, because an app update is the event this
|
|
5957
|
+
* column exists to catch and waiting a minute to notice it serves nobody. A
|
|
5958
|
+
* version that did not change writes nothing extra — the UPDATE the throttle
|
|
5959
|
+
* was already going to do carries it.
|
|
5960
|
+
*
|
|
5961
|
+
* `clientSeenAt` moves only when one of the three values differs from what is
|
|
5962
|
+
* stored, so it answers "since when has this device been on this release"
|
|
5963
|
+
* rather than "when was it last seen", which lastUsedAt already answers.
|
|
5919
5964
|
*/
|
|
5920
|
-
async updateLastUsedById(id12) {
|
|
5965
|
+
async updateLastUsedById(id12, identity) {
|
|
5921
5966
|
const staleBefore = new Date(Date.now() - LAST_USED_THROTTLE_MS);
|
|
5967
|
+
const lastUsedIsStale = or(
|
|
5968
|
+
isNull(userPublicKeys.lastUsedAt),
|
|
5969
|
+
lt(userPublicKeys.lastUsedAt, staleBefore)
|
|
5970
|
+
);
|
|
5971
|
+
if (!identity) {
|
|
5972
|
+
await this.db.update(userPublicKeys).set({ lastUsedAt: /* @__PURE__ */ new Date() }).where(and2(eq2(userPublicKeys.id, id12), lastUsedIsStale));
|
|
5973
|
+
return;
|
|
5974
|
+
}
|
|
5975
|
+
const identityChanged = sql3`(
|
|
5976
|
+
${userPublicKeys.clientKind} IS DISTINCT FROM ${identity.kind}
|
|
5977
|
+
OR ${userPublicKeys.clientVersion} IS DISTINCT FROM ${identity.version}
|
|
5978
|
+
OR ${userPublicKeys.clientContractVersion} IS DISTINCT FROM ${identity.contractVersion}
|
|
5979
|
+
)`;
|
|
5980
|
+
const now = /* @__PURE__ */ new Date();
|
|
5981
|
+
const nowParam = sql3`${now.toISOString()}::timestamptz`;
|
|
5922
5982
|
await this.db.update(userPublicKeys).set({
|
|
5923
|
-
lastUsedAt:
|
|
5983
|
+
lastUsedAt: now,
|
|
5984
|
+
clientKind: identity.kind,
|
|
5985
|
+
clientVersion: identity.version,
|
|
5986
|
+
clientContractVersion: identity.contractVersion,
|
|
5987
|
+
clientSeenAt: sql3`CASE WHEN ${identityChanged} THEN ${nowParam} ELSE ${userPublicKeys.clientSeenAt} END`
|
|
5924
5988
|
}).where(and2(
|
|
5925
5989
|
eq2(userPublicKeys.id, id12),
|
|
5926
|
-
or(
|
|
5927
|
-
isNull(userPublicKeys.lastUsedAt),
|
|
5928
|
-
lt(userPublicKeys.lastUsedAt, staleBefore)
|
|
5929
|
-
)
|
|
5990
|
+
or(lastUsedIsStale, identityChanged)
|
|
5930
5991
|
));
|
|
5931
5992
|
}
|
|
5932
5993
|
};
|
|
@@ -6511,7 +6572,7 @@ var init_user_profiles_repository = __esm({
|
|
|
6511
6572
|
});
|
|
6512
6573
|
|
|
6513
6574
|
// src/server/repositories/invitations.repository.ts
|
|
6514
|
-
import { eq as eq9, and as and6, lt as lt4, desc as desc2, sql as
|
|
6575
|
+
import { eq as eq9, and as and6, lt as lt4, desc as desc2, sql as sql4 } from "drizzle-orm";
|
|
6515
6576
|
import { BaseRepository as BaseRepository9 } from "@spfn/core/db";
|
|
6516
6577
|
var InvitationsRepository, invitationsRepository;
|
|
6517
6578
|
var init_invitations_repository = __esm({
|
|
@@ -6653,7 +6714,7 @@ var init_invitations_repository = __esm({
|
|
|
6653
6714
|
conditions.push(eq9(userInvitations.invitedBy, invitedBy));
|
|
6654
6715
|
}
|
|
6655
6716
|
const whereClause = conditions.length > 0 ? and6(...conditions) : void 0;
|
|
6656
|
-
const countResult = await this.readDb.select({ count:
|
|
6717
|
+
const countResult = await this.readDb.select({ count: sql4`count(*)` }).from(userInvitations).where(whereClause);
|
|
6657
6718
|
const total = Number(countResult[0]?.count || 0);
|
|
6658
6719
|
const results = await this.readDb.select({
|
|
6659
6720
|
id: userInvitations.id,
|
|
@@ -11094,21 +11155,8 @@ import {
|
|
|
11094
11155
|
KeyExpiredError
|
|
11095
11156
|
} from "@spfn/auth/errors";
|
|
11096
11157
|
|
|
11097
|
-
// src/server/
|
|
11098
|
-
import {
|
|
11099
|
-
BadRequestError as BadRequestError2,
|
|
11100
|
-
ConflictError as ConflictError2,
|
|
11101
|
-
ServiceUnavailableError,
|
|
11102
|
-
UnauthorizedError
|
|
11103
|
-
} from "@spfn/core/errors";
|
|
11104
|
-
import {
|
|
11105
|
-
authLogger as authLogger2,
|
|
11106
|
-
keysRepository as keysRepository2,
|
|
11107
|
-
usersRepository as usersRepository2,
|
|
11108
|
-
userProfilesRepository as userProfilesRepository2,
|
|
11109
|
-
getPendingDeletionInfo as getPendingDeletionInfo2
|
|
11110
|
-
} from "@spfn/auth/server";
|
|
11111
|
-
import { AccountDisabledError as AccountDisabledError3, AccountPendingDeletionError as AccountPendingDeletionError3 } from "@spfn/auth/errors";
|
|
11158
|
+
// src/server/client-proof/refusal.ts
|
|
11159
|
+
import { randomBytes } from "crypto";
|
|
11112
11160
|
|
|
11113
11161
|
// src/server/client-proof/canonical-json.ts
|
|
11114
11162
|
var CanonicalJsonError = class extends Error {
|
|
@@ -11456,82 +11504,7 @@ function encodeString(value) {
|
|
|
11456
11504
|
return out + '"';
|
|
11457
11505
|
}
|
|
11458
11506
|
|
|
11459
|
-
// src/server/client-proof/proof.ts
|
|
11460
|
-
import { createHash as createHash5, createPrivateKey, createPublicKey, sign, verify as verify2 } from "crypto";
|
|
11461
|
-
var CLIENT_PROOF_PROFILE = "clientProofV1";
|
|
11462
|
-
var ABSENT_BODY_SHA256 = "0".repeat(64);
|
|
11463
|
-
var DEFAULT_REPLAY_WINDOW_MILLIS = 3e5;
|
|
11464
|
-
var PROOF_INPUT_FIELDS = [
|
|
11465
|
-
"profile",
|
|
11466
|
-
"method",
|
|
11467
|
-
"path",
|
|
11468
|
-
"clientId",
|
|
11469
|
-
"keyId",
|
|
11470
|
-
"nonce",
|
|
11471
|
-
"issuedAtMillis",
|
|
11472
|
-
"bodySha256"
|
|
11473
|
-
];
|
|
11474
|
-
var PROOF_INPUT_SEPARATOR = "\n";
|
|
11475
|
-
var PROOF_SIGNATURE_BYTES = 64;
|
|
11476
|
-
var PROOF_SIGNATURE_HEX_LENGTH = PROOF_SIGNATURE_BYTES * 2;
|
|
11477
|
-
var PROOF_SIGNATURE_PATTERN = /^[0-9a-f]{128}$/;
|
|
11478
|
-
var RAW_SIGNATURE_ENCODING = "ieee-p1363";
|
|
11479
|
-
var ProofInputError = class extends Error {
|
|
11480
|
-
constructor() {
|
|
11481
|
-
super("proof input field contains a C0 control character");
|
|
11482
|
-
this.name = "ProofInputError";
|
|
11483
|
-
}
|
|
11484
|
-
};
|
|
11485
|
-
function canonicalProofInput(input) {
|
|
11486
|
-
const values = {
|
|
11487
|
-
profile: CLIENT_PROOF_PROFILE,
|
|
11488
|
-
method: input.method,
|
|
11489
|
-
path: input.path,
|
|
11490
|
-
clientId: input.clientId,
|
|
11491
|
-
keyId: input.keyId,
|
|
11492
|
-
nonce: input.nonce,
|
|
11493
|
-
issuedAtMillis: input.issuedAtMillis.toString(),
|
|
11494
|
-
bodySha256: input.bodySha256
|
|
11495
|
-
};
|
|
11496
|
-
const fields = PROOF_INPUT_FIELDS.map((name) => values[name]);
|
|
11497
|
-
for (const field of fields) {
|
|
11498
|
-
for (const ch of field) {
|
|
11499
|
-
if (ch.codePointAt(0) < 32) {
|
|
11500
|
-
throw new ProofInputError();
|
|
11501
|
-
}
|
|
11502
|
-
}
|
|
11503
|
-
}
|
|
11504
|
-
return fields.join(PROOF_INPUT_SEPARATOR);
|
|
11505
|
-
}
|
|
11506
|
-
function parseClientProofPublicKey(spkiDerBase64) {
|
|
11507
|
-
const key = createPublicKey({
|
|
11508
|
-
key: Buffer.from(spkiDerBase64, "base64"),
|
|
11509
|
-
format: "der",
|
|
11510
|
-
type: "spki"
|
|
11511
|
-
});
|
|
11512
|
-
if (key.asymmetricKeyType !== "ec" || key.asymmetricKeyDetails?.namedCurve !== "prime256v1") {
|
|
11513
|
-
throw new Error("a clientProofV1 public key must be an ECDSA P-256 key");
|
|
11514
|
-
}
|
|
11515
|
-
return key;
|
|
11516
|
-
}
|
|
11517
|
-
function verifyClientProof(input, presentedProof, publicKey) {
|
|
11518
|
-
const data = Buffer.from(canonicalProofInput(input), "utf8");
|
|
11519
|
-
if (!PROOF_SIGNATURE_PATTERN.test(presentedProof)) {
|
|
11520
|
-
return false;
|
|
11521
|
-
}
|
|
11522
|
-
return verify2(
|
|
11523
|
-
"sha256",
|
|
11524
|
-
data,
|
|
11525
|
-
{ key: publicKey, dsaEncoding: RAW_SIGNATURE_ENCODING },
|
|
11526
|
-
Buffer.from(presentedProof, "hex")
|
|
11527
|
-
);
|
|
11528
|
-
}
|
|
11529
|
-
function sha256Hex(bytes) {
|
|
11530
|
-
return createHash5("sha256").update(bytes).digest("hex");
|
|
11531
|
-
}
|
|
11532
|
-
|
|
11533
11507
|
// src/server/client-proof/refusal.ts
|
|
11534
|
-
import { randomBytes } from "crypto";
|
|
11535
11508
|
var HTTP_STATUS = {
|
|
11536
11509
|
PROOF_INVALID: 401,
|
|
11537
11510
|
PROOF_REPLAYED: 401,
|
|
@@ -11540,6 +11513,9 @@ var HTTP_STATUS = {
|
|
|
11540
11513
|
PROFILE_REJECTED: 400,
|
|
11541
11514
|
CONTRACT_UNSUPPORTED: 409
|
|
11542
11515
|
};
|
|
11516
|
+
function newHexId() {
|
|
11517
|
+
return randomBytes(16).toString("hex");
|
|
11518
|
+
}
|
|
11543
11519
|
var ClientProofRefusal = class _ClientProofRefusal {
|
|
11544
11520
|
constructor(code, message) {
|
|
11545
11521
|
this.code = code;
|
|
@@ -11609,6 +11585,18 @@ var ClientProofRefusal = class _ClientProofRefusal {
|
|
|
11609
11585
|
static profileRejected() {
|
|
11610
11586
|
return new _ClientProofRefusal("PROFILE_REJECTED", "the named auth profile is not on this contract's allowlist");
|
|
11611
11587
|
}
|
|
11588
|
+
/**
|
|
11589
|
+
* A request that names a profile and presents Bearer credentials as well.
|
|
11590
|
+
* The profile named is a real one, so this is not a shape the two ends
|
|
11591
|
+
* disagree about: the request asked to be authenticated two ways at once
|
|
11592
|
+
* and the profile it named is the one refused.
|
|
11593
|
+
*/
|
|
11594
|
+
static credentialsMixed() {
|
|
11595
|
+
return new _ClientProofRefusal(
|
|
11596
|
+
"PROFILE_REJECTED",
|
|
11597
|
+
"an auth profile and Bearer credentials must not be mixed in one request"
|
|
11598
|
+
);
|
|
11599
|
+
}
|
|
11612
11600
|
// ---- auth: a new session might clear it (rule 1) -------------------------
|
|
11613
11601
|
static sessionRevoked() {
|
|
11614
11602
|
return new _ClientProofRefusal("SESSION_REVOKED", "the key or session was revoked");
|
|
@@ -11627,6 +11615,84 @@ function contractViolation(message) {
|
|
|
11627
11615
|
return new ClientProofRefusal("CONTRACT_UNSUPPORTED", message);
|
|
11628
11616
|
}
|
|
11629
11617
|
|
|
11618
|
+
// src/server/client-proof/contract-bundle.ts
|
|
11619
|
+
import { createHash as createHash6 } from "crypto";
|
|
11620
|
+
init_types();
|
|
11621
|
+
|
|
11622
|
+
// src/server/client-proof/proof.ts
|
|
11623
|
+
import { createHash as createHash5, createPrivateKey, createPublicKey, sign, verify as verify2 } from "crypto";
|
|
11624
|
+
var CLIENT_PROOF_PROFILE = "clientProofV1";
|
|
11625
|
+
var ABSENT_BODY_SHA256 = "0".repeat(64);
|
|
11626
|
+
var DEFAULT_REPLAY_WINDOW_MILLIS = 3e5;
|
|
11627
|
+
var PROOF_INPUT_FIELDS = [
|
|
11628
|
+
"profile",
|
|
11629
|
+
"method",
|
|
11630
|
+
"path",
|
|
11631
|
+
"clientId",
|
|
11632
|
+
"keyId",
|
|
11633
|
+
"nonce",
|
|
11634
|
+
"issuedAtMillis",
|
|
11635
|
+
"bodySha256"
|
|
11636
|
+
];
|
|
11637
|
+
var PROOF_INPUT_SEPARATOR = "\n";
|
|
11638
|
+
var PROOF_SIGNATURE_BYTES = 64;
|
|
11639
|
+
var PROOF_SIGNATURE_HEX_LENGTH = PROOF_SIGNATURE_BYTES * 2;
|
|
11640
|
+
var PROOF_SIGNATURE_PATTERN = /^[0-9a-f]{128}$/;
|
|
11641
|
+
var RAW_SIGNATURE_ENCODING = "ieee-p1363";
|
|
11642
|
+
var ProofInputError = class extends Error {
|
|
11643
|
+
constructor() {
|
|
11644
|
+
super("proof input field contains a C0 control character");
|
|
11645
|
+
this.name = "ProofInputError";
|
|
11646
|
+
}
|
|
11647
|
+
};
|
|
11648
|
+
function canonicalProofInput(input) {
|
|
11649
|
+
const values = {
|
|
11650
|
+
profile: CLIENT_PROOF_PROFILE,
|
|
11651
|
+
method: input.method,
|
|
11652
|
+
path: input.path,
|
|
11653
|
+
clientId: input.clientId,
|
|
11654
|
+
keyId: input.keyId,
|
|
11655
|
+
nonce: input.nonce,
|
|
11656
|
+
issuedAtMillis: input.issuedAtMillis.toString(),
|
|
11657
|
+
bodySha256: input.bodySha256
|
|
11658
|
+
};
|
|
11659
|
+
const fields = PROOF_INPUT_FIELDS.map((name) => values[name]);
|
|
11660
|
+
for (const field of fields) {
|
|
11661
|
+
for (const ch of field) {
|
|
11662
|
+
if (ch.codePointAt(0) < 32) {
|
|
11663
|
+
throw new ProofInputError();
|
|
11664
|
+
}
|
|
11665
|
+
}
|
|
11666
|
+
}
|
|
11667
|
+
return fields.join(PROOF_INPUT_SEPARATOR);
|
|
11668
|
+
}
|
|
11669
|
+
function parseClientProofPublicKey(spkiDerBase64) {
|
|
11670
|
+
const key = createPublicKey({
|
|
11671
|
+
key: Buffer.from(spkiDerBase64, "base64"),
|
|
11672
|
+
format: "der",
|
|
11673
|
+
type: "spki"
|
|
11674
|
+
});
|
|
11675
|
+
if (key.asymmetricKeyType !== "ec" || key.asymmetricKeyDetails?.namedCurve !== "prime256v1") {
|
|
11676
|
+
throw new Error("a clientProofV1 public key must be an ECDSA P-256 key");
|
|
11677
|
+
}
|
|
11678
|
+
return key;
|
|
11679
|
+
}
|
|
11680
|
+
function verifyClientProof(input, presentedProof, publicKey) {
|
|
11681
|
+
const data = Buffer.from(canonicalProofInput(input), "utf8");
|
|
11682
|
+
if (!PROOF_SIGNATURE_PATTERN.test(presentedProof)) {
|
|
11683
|
+
return false;
|
|
11684
|
+
}
|
|
11685
|
+
return verify2(
|
|
11686
|
+
"sha256",
|
|
11687
|
+
data,
|
|
11688
|
+
{ key: publicKey, dsaEncoding: RAW_SIGNATURE_ENCODING },
|
|
11689
|
+
Buffer.from(presentedProof, "hex")
|
|
11690
|
+
);
|
|
11691
|
+
}
|
|
11692
|
+
function sha256Hex(bytes) {
|
|
11693
|
+
return createHash5("sha256").update(bytes).digest("hex");
|
|
11694
|
+
}
|
|
11695
|
+
|
|
11630
11696
|
// src/server/client-proof/admission.ts
|
|
11631
11697
|
var CLIENT_PROOF_HEADERS = {
|
|
11632
11698
|
profile: "x-spfn-auth-profile",
|
|
@@ -11681,6 +11747,253 @@ function isRequestContentType(value) {
|
|
|
11681
11747
|
return value.split(";")[0].trim().toLowerCase() === CLIENT_PROOF_CONTENT_TYPE;
|
|
11682
11748
|
}
|
|
11683
11749
|
|
|
11750
|
+
// src/server/client-proof/contract-bundle.ts
|
|
11751
|
+
init_wire_headers();
|
|
11752
|
+
var CONTRACT_VERSION = "0.8.0";
|
|
11753
|
+
var CONTRACT_SUPPORTED_RANGE = ">=0.8.0 <0.9.0";
|
|
11754
|
+
function required(name, type) {
|
|
11755
|
+
return { name, type, optional: false };
|
|
11756
|
+
}
|
|
11757
|
+
function optional(name, type) {
|
|
11758
|
+
return { name, type, optional: true };
|
|
11759
|
+
}
|
|
11760
|
+
var CONTRACT_TYPES = [
|
|
11761
|
+
{
|
|
11762
|
+
name: "HandshakeRequest",
|
|
11763
|
+
fields: [
|
|
11764
|
+
required("clientId", "string"),
|
|
11765
|
+
required("keyId", "string"),
|
|
11766
|
+
required("nonce", "string"),
|
|
11767
|
+
required("issuedAtMillis", "integer")
|
|
11768
|
+
]
|
|
11769
|
+
},
|
|
11770
|
+
{
|
|
11771
|
+
name: "HandshakeResponse",
|
|
11772
|
+
fields: [
|
|
11773
|
+
required("sessionId", "string"),
|
|
11774
|
+
required("expiresAtMillis", "integer")
|
|
11775
|
+
]
|
|
11776
|
+
},
|
|
11777
|
+
{
|
|
11778
|
+
name: "EchoRequest",
|
|
11779
|
+
fields: [
|
|
11780
|
+
required("message", "string"),
|
|
11781
|
+
required("sequence", "integer")
|
|
11782
|
+
]
|
|
11783
|
+
},
|
|
11784
|
+
{
|
|
11785
|
+
name: "EchoResponse",
|
|
11786
|
+
fields: [
|
|
11787
|
+
required("message", "string"),
|
|
11788
|
+
required("sequence", "integer"),
|
|
11789
|
+
required("serverTimeMillis", "integer")
|
|
11790
|
+
]
|
|
11791
|
+
},
|
|
11792
|
+
{
|
|
11793
|
+
name: "ListItemsRequest",
|
|
11794
|
+
fields: [
|
|
11795
|
+
required("limit", "integer"),
|
|
11796
|
+
optional("cursor", "string")
|
|
11797
|
+
]
|
|
11798
|
+
},
|
|
11799
|
+
{
|
|
11800
|
+
name: "Item",
|
|
11801
|
+
fields: [
|
|
11802
|
+
required("id", "string"),
|
|
11803
|
+
required("name", "string"),
|
|
11804
|
+
required("updatedAtMillis", "integer")
|
|
11805
|
+
]
|
|
11806
|
+
},
|
|
11807
|
+
{
|
|
11808
|
+
name: "ListItemsResponse",
|
|
11809
|
+
fields: [
|
|
11810
|
+
required("items", "array<Item>"),
|
|
11811
|
+
optional("nextCursor", "string")
|
|
11812
|
+
]
|
|
11813
|
+
},
|
|
11814
|
+
{
|
|
11815
|
+
name: "RegisterRequest",
|
|
11816
|
+
fields: [
|
|
11817
|
+
optional("email", "string"),
|
|
11818
|
+
optional("phone", "string"),
|
|
11819
|
+
required("verificationToken", "string"),
|
|
11820
|
+
required("password", "string"),
|
|
11821
|
+
required("publicKey", "string"),
|
|
11822
|
+
required("keyId", "string"),
|
|
11823
|
+
required("fingerprint", "string"),
|
|
11824
|
+
required("algorithm", "KeyAlgorithm")
|
|
11825
|
+
]
|
|
11826
|
+
},
|
|
11827
|
+
{
|
|
11828
|
+
name: "RegisterResponse",
|
|
11829
|
+
fields: [
|
|
11830
|
+
required("userId", "string"),
|
|
11831
|
+
required("publicId", "string"),
|
|
11832
|
+
optional("email", "string"),
|
|
11833
|
+
optional("phone", "string")
|
|
11834
|
+
]
|
|
11835
|
+
},
|
|
11836
|
+
{
|
|
11837
|
+
name: "LoginRequest",
|
|
11838
|
+
fields: [
|
|
11839
|
+
optional("email", "string"),
|
|
11840
|
+
optional("phone", "string"),
|
|
11841
|
+
required("password", "string"),
|
|
11842
|
+
required("publicKey", "string"),
|
|
11843
|
+
required("keyId", "string"),
|
|
11844
|
+
required("fingerprint", "string"),
|
|
11845
|
+
required("algorithm", "KeyAlgorithm"),
|
|
11846
|
+
optional("oldKeyId", "string")
|
|
11847
|
+
]
|
|
11848
|
+
},
|
|
11849
|
+
{
|
|
11850
|
+
name: "LoginResponse",
|
|
11851
|
+
fields: [
|
|
11852
|
+
required("userId", "string"),
|
|
11853
|
+
required("publicId", "string"),
|
|
11854
|
+
optional("email", "string"),
|
|
11855
|
+
optional("phone", "string"),
|
|
11856
|
+
required("passwordChangeRequired", "boolean")
|
|
11857
|
+
]
|
|
11858
|
+
},
|
|
11859
|
+
{
|
|
11860
|
+
name: "OauthNativeRequest",
|
|
11861
|
+
fields: [
|
|
11862
|
+
required("idToken", "string"),
|
|
11863
|
+
required("nonce", "string"),
|
|
11864
|
+
optional("accessToken", "string"),
|
|
11865
|
+
required("publicKey", "string"),
|
|
11866
|
+
required("keyId", "string"),
|
|
11867
|
+
required("fingerprint", "string"),
|
|
11868
|
+
required("algorithm", "KeyAlgorithm")
|
|
11869
|
+
]
|
|
11870
|
+
},
|
|
11871
|
+
{
|
|
11872
|
+
name: "OauthNativeResponse",
|
|
11873
|
+
fields: [
|
|
11874
|
+
required("userId", "string"),
|
|
11875
|
+
required("keyId", "string"),
|
|
11876
|
+
required("isNewUser", "boolean")
|
|
11877
|
+
]
|
|
11878
|
+
},
|
|
11879
|
+
{
|
|
11880
|
+
name: "RotateKeyRequest",
|
|
11881
|
+
fields: [
|
|
11882
|
+
required("publicKey", "string"),
|
|
11883
|
+
required("keyId", "string"),
|
|
11884
|
+
required("fingerprint", "string"),
|
|
11885
|
+
required("algorithm", "KeyAlgorithm")
|
|
11886
|
+
]
|
|
11887
|
+
},
|
|
11888
|
+
{
|
|
11889
|
+
name: "RotateKeyResponse",
|
|
11890
|
+
fields: [
|
|
11891
|
+
required("success", "boolean"),
|
|
11892
|
+
required("keyId", "string")
|
|
11893
|
+
]
|
|
11894
|
+
},
|
|
11895
|
+
{
|
|
11896
|
+
name: "ListKeysRequest",
|
|
11897
|
+
fields: [
|
|
11898
|
+
optional("includeRevoked", "boolean")
|
|
11899
|
+
]
|
|
11900
|
+
},
|
|
11901
|
+
{
|
|
11902
|
+
name: "KeySummary",
|
|
11903
|
+
fields: [
|
|
11904
|
+
required("keyId", "string"),
|
|
11905
|
+
optional("deviceName", "string"),
|
|
11906
|
+
optional("platform", "string"),
|
|
11907
|
+
required("algorithm", "KeyAlgorithm"),
|
|
11908
|
+
required("fingerprintPrefix", "string"),
|
|
11909
|
+
required("createdAtMillis", "integer"),
|
|
11910
|
+
optional("lastUsedAtMillis", "integer"),
|
|
11911
|
+
optional("expiresAtMillis", "integer"),
|
|
11912
|
+
required("isExpired", "boolean"),
|
|
11913
|
+
required("isActive", "boolean"),
|
|
11914
|
+
optional("revokedAtMillis", "integer")
|
|
11915
|
+
]
|
|
11916
|
+
},
|
|
11917
|
+
{
|
|
11918
|
+
name: "ListKeysResponse",
|
|
11919
|
+
fields: [
|
|
11920
|
+
required("keys", "array<KeySummary>")
|
|
11921
|
+
]
|
|
11922
|
+
},
|
|
11923
|
+
{
|
|
11924
|
+
name: "RevokeKeyRequest",
|
|
11925
|
+
fields: [
|
|
11926
|
+
required("keyId", "string")
|
|
11927
|
+
]
|
|
11928
|
+
},
|
|
11929
|
+
{
|
|
11930
|
+
name: "RevokeKeyResponse",
|
|
11931
|
+
fields: [
|
|
11932
|
+
required("keyId", "string"),
|
|
11933
|
+
required("selfRevoked", "boolean")
|
|
11934
|
+
]
|
|
11935
|
+
},
|
|
11936
|
+
{
|
|
11937
|
+
name: "RevokeAllKeysRequest",
|
|
11938
|
+
fields: [
|
|
11939
|
+
optional("includeCurrent", "boolean")
|
|
11940
|
+
]
|
|
11941
|
+
},
|
|
11942
|
+
{
|
|
11943
|
+
name: "RevokeAllKeysResponse",
|
|
11944
|
+
fields: [
|
|
11945
|
+
required("revokedCount", "integer"),
|
|
11946
|
+
required("currentKeyRevoked", "boolean")
|
|
11947
|
+
]
|
|
11948
|
+
}
|
|
11949
|
+
];
|
|
11950
|
+
var CONTRACT_ENUMS = [
|
|
11951
|
+
{ name: "KeyAlgorithm", values: [...KEY_ALGORITHM] }
|
|
11952
|
+
];
|
|
11953
|
+
var BUNDLE_FILENAME = "spfn-mobile-contract.json";
|
|
11954
|
+
var BUNDLE_REPO_PATH = `contracts/mobile/${BUNDLE_FILENAME}`;
|
|
11955
|
+
|
|
11956
|
+
// src/server/client-proof/wire-version.ts
|
|
11957
|
+
init_wire_headers();
|
|
11958
|
+
init_wire_headers();
|
|
11959
|
+
function serverContractHeaders() {
|
|
11960
|
+
return {
|
|
11961
|
+
[SERVER_CONTRACT_HEADERS.version]: CONTRACT_VERSION,
|
|
11962
|
+
[SERVER_CONTRACT_HEADERS.supportedRange]: CONTRACT_SUPPORTED_RANGE
|
|
11963
|
+
};
|
|
11964
|
+
}
|
|
11965
|
+
|
|
11966
|
+
// src/server/client-proof/version-middleware.ts
|
|
11967
|
+
var CLIENT_IDENTITY_CONTEXT_KEY = "clientIdentity";
|
|
11968
|
+
function readContextClientIdentity(c) {
|
|
11969
|
+
return c.get(CLIENT_IDENTITY_CONTEXT_KEY) ?? null;
|
|
11970
|
+
}
|
|
11971
|
+
|
|
11972
|
+
// src/server/middleware/auth-profiles.ts
|
|
11973
|
+
import {
|
|
11974
|
+
SerializableError,
|
|
11975
|
+
ServiceUnavailableError,
|
|
11976
|
+
UnauthorizedError
|
|
11977
|
+
} from "@spfn/core/errors";
|
|
11978
|
+
import {
|
|
11979
|
+
authLogger as authLogger2,
|
|
11980
|
+
keysRepository as keysRepository2,
|
|
11981
|
+
usersRepository as usersRepository2,
|
|
11982
|
+
userProfilesRepository as userProfilesRepository2,
|
|
11983
|
+
getPendingDeletionInfo as getPendingDeletionInfo2
|
|
11984
|
+
} from "@spfn/auth/server";
|
|
11985
|
+
import { AccountDisabledError as AccountDisabledError3, AccountPendingDeletionError as AccountPendingDeletionError3 } from "@spfn/auth/errors";
|
|
11986
|
+
|
|
11987
|
+
// src/server/client-proof/refusal-response.ts
|
|
11988
|
+
function clientProofRefusalResponse(c, refusal) {
|
|
11989
|
+
const bytes = refusal.envelopeBytes(newHexId());
|
|
11990
|
+
const buffer = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
|
11991
|
+
return c.newResponse(buffer, refusal.httpStatus, {
|
|
11992
|
+
"content-type": "application/json",
|
|
11993
|
+
...serverContractHeaders()
|
|
11994
|
+
});
|
|
11995
|
+
}
|
|
11996
|
+
|
|
11684
11997
|
// src/server/client-proof/replay-store.ts
|
|
11685
11998
|
import { getCache } from "@spfn/core/cache";
|
|
11686
11999
|
function replayLedgerKey(clientId, nonce) {
|
|
@@ -11744,10 +12057,7 @@ function selectAuthProfile(c) {
|
|
|
11744
12057
|
return null;
|
|
11745
12058
|
}
|
|
11746
12059
|
if (c.req.header("Authorization") !== void 0) {
|
|
11747
|
-
throw
|
|
11748
|
-
message: "an auth profile and Bearer credentials must not be mixed in one request",
|
|
11749
|
-
details: { code: "PROFILE_REJECTED" }
|
|
11750
|
-
});
|
|
12060
|
+
throw refusalError(ClientProofRefusal.credentialsMixed());
|
|
11751
12061
|
}
|
|
11752
12062
|
const verifier = AUTH_PROFILE_VERIFIERS.get(profile);
|
|
11753
12063
|
if (verifier === void 0) {
|
|
@@ -11773,15 +12083,34 @@ async function resolveAuthenticatedUser(userId) {
|
|
|
11773
12083
|
}
|
|
11774
12084
|
return { user, role: role?.name ?? null, locale };
|
|
11775
12085
|
}
|
|
11776
|
-
|
|
11777
|
-
|
|
11778
|
-
|
|
11779
|
-
|
|
12086
|
+
var ClientProofRefusalError = class extends SerializableError {
|
|
12087
|
+
constructor(refusal) {
|
|
12088
|
+
super(refusal.message);
|
|
12089
|
+
this.refusal = refusal;
|
|
12090
|
+
this.name = "ClientProofRefusalError";
|
|
12091
|
+
this.statusCode = refusal.httpStatus;
|
|
11780
12092
|
}
|
|
11781
|
-
|
|
11782
|
-
|
|
12093
|
+
statusCode;
|
|
12094
|
+
toJSON() {
|
|
12095
|
+
return { __type: this.refusal.code, message: this.message };
|
|
12096
|
+
}
|
|
12097
|
+
};
|
|
12098
|
+
function refusalError(refusal) {
|
|
12099
|
+
return new ClientProofRefusalError(refusal);
|
|
12100
|
+
}
|
|
12101
|
+
async function runAuthProfile(c) {
|
|
12102
|
+
try {
|
|
12103
|
+
const verifier = selectAuthProfile(c);
|
|
12104
|
+
if (verifier === null) {
|
|
12105
|
+
return { kind: "none" };
|
|
12106
|
+
}
|
|
12107
|
+
return { kind: "authenticated", auth: await verifier.verify(c) };
|
|
12108
|
+
} catch (err) {
|
|
12109
|
+
if (err instanceof ClientProofRefusalError) {
|
|
12110
|
+
return { kind: "refused", response: clientProofRefusalResponse(c, err.refusal) };
|
|
12111
|
+
}
|
|
12112
|
+
throw err;
|
|
11783
12113
|
}
|
|
11784
|
-
return new UnauthorizedError(data);
|
|
11785
12114
|
}
|
|
11786
12115
|
async function failClosed(operation) {
|
|
11787
12116
|
try {
|
|
@@ -11841,7 +12170,7 @@ async function verifyClientProofProfile(c) {
|
|
|
11841
12170
|
throw refusalError(ClientProofRefusal.proofReplayed());
|
|
11842
12171
|
}
|
|
11843
12172
|
const { user, role, locale } = await resolveAuthenticatedUser(keyRecord.userId);
|
|
11844
|
-
keysRepository2.updateLastUsedById(keyRecord.id).catch((err) => authLogger2.middleware.error("Failed to update lastUsedAt", err));
|
|
12173
|
+
keysRepository2.updateLastUsedById(keyRecord.id, readContextClientIdentity(c)).catch((err) => authLogger2.middleware.error("Failed to update lastUsedAt", err));
|
|
11845
12174
|
authLogger2.middleware.info("API access", {
|
|
11846
12175
|
userId: user.id,
|
|
11847
12176
|
email: user.email,
|
|
@@ -11900,11 +12229,14 @@ var AUTH_PROFILE_VERIFIERS = /* @__PURE__ */ new Map([
|
|
|
11900
12229
|
|
|
11901
12230
|
// src/server/middleware/authenticate.ts
|
|
11902
12231
|
var authenticate = defineMiddleware("auth", async (c, next) => {
|
|
11903
|
-
const
|
|
11904
|
-
if (
|
|
11905
|
-
|
|
12232
|
+
const profile = await runAuthProfile(c);
|
|
12233
|
+
if (profile.kind === "refused") {
|
|
12234
|
+
return profile.response;
|
|
12235
|
+
}
|
|
12236
|
+
if (profile.kind === "authenticated") {
|
|
12237
|
+
c.set("auth", profile.auth);
|
|
11906
12238
|
await next();
|
|
11907
|
-
return;
|
|
12239
|
+
return void 0;
|
|
11908
12240
|
}
|
|
11909
12241
|
const authHeader = c.req.header("Authorization");
|
|
11910
12242
|
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
|
@@ -11946,7 +12278,7 @@ var authenticate = defineMiddleware("auth", async (c, next) => {
|
|
|
11946
12278
|
throw new UnauthorizedError2({ message: "Authentication failed" });
|
|
11947
12279
|
}
|
|
11948
12280
|
const { user, role, locale } = await resolveAuthenticatedUser(keyRecord.userId);
|
|
11949
|
-
keysRepository3.updateLastUsedById(keyRecord.id).catch((err) => authLogger3.middleware.error("Failed to update lastUsedAt", err));
|
|
12281
|
+
keysRepository3.updateLastUsedById(keyRecord.id, readContextClientIdentity(c)).catch((err) => authLogger3.middleware.error("Failed to update lastUsedAt", err));
|
|
11950
12282
|
c.set("auth", {
|
|
11951
12283
|
user,
|
|
11952
12284
|
userId: String(user.id),
|
|
@@ -11967,35 +12299,39 @@ var authenticate = defineMiddleware("auth", async (c, next) => {
|
|
|
11967
12299
|
userAgent: c.req.header("user-agent")
|
|
11968
12300
|
});
|
|
11969
12301
|
await next();
|
|
12302
|
+
return void 0;
|
|
11970
12303
|
});
|
|
11971
12304
|
var optionalAuth = defineMiddleware("optionalAuth", async (c, next) => {
|
|
11972
|
-
const
|
|
11973
|
-
if (
|
|
11974
|
-
|
|
12305
|
+
const profile = await runAuthProfile(c);
|
|
12306
|
+
if (profile.kind === "refused") {
|
|
12307
|
+
return profile.response;
|
|
12308
|
+
}
|
|
12309
|
+
if (profile.kind === "authenticated") {
|
|
12310
|
+
c.set("auth", profile.auth);
|
|
11975
12311
|
await next();
|
|
11976
|
-
return;
|
|
12312
|
+
return void 0;
|
|
11977
12313
|
}
|
|
11978
12314
|
const authHeader = c.req.header("Authorization");
|
|
11979
12315
|
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
|
11980
12316
|
await next();
|
|
11981
|
-
return;
|
|
12317
|
+
return void 0;
|
|
11982
12318
|
}
|
|
11983
12319
|
const token = authHeader.substring(7);
|
|
11984
12320
|
try {
|
|
11985
12321
|
const decoded = decodeToken2(token);
|
|
11986
12322
|
if (!decoded || !decoded.keyId) {
|
|
11987
12323
|
await next();
|
|
11988
|
-
return;
|
|
12324
|
+
return void 0;
|
|
11989
12325
|
}
|
|
11990
12326
|
const keyId = decoded.keyId;
|
|
11991
12327
|
const keyRecord = await keysRepository3.findActiveByKeyId(keyId);
|
|
11992
12328
|
if (!keyRecord) {
|
|
11993
12329
|
await next();
|
|
11994
|
-
return;
|
|
12330
|
+
return void 0;
|
|
11995
12331
|
}
|
|
11996
12332
|
if (keyRecord.expiresAt && /* @__PURE__ */ new Date() > keyRecord.expiresAt) {
|
|
11997
12333
|
await next();
|
|
11998
|
-
return;
|
|
12334
|
+
return void 0;
|
|
11999
12335
|
}
|
|
12000
12336
|
verifyClientToken2(
|
|
12001
12337
|
token,
|
|
@@ -12008,10 +12344,10 @@ var optionalAuth = defineMiddleware("optionalAuth", async (c, next) => {
|
|
|
12008
12344
|
]);
|
|
12009
12345
|
if (!result || result.user.status !== "active") {
|
|
12010
12346
|
await next();
|
|
12011
|
-
return;
|
|
12347
|
+
return void 0;
|
|
12012
12348
|
}
|
|
12013
12349
|
const { user, role } = result;
|
|
12014
|
-
keysRepository3.updateLastUsedById(keyRecord.id).catch((err) => authLogger3.middleware.error("Failed to update lastUsedAt", err));
|
|
12350
|
+
keysRepository3.updateLastUsedById(keyRecord.id, readContextClientIdentity(c)).catch((err) => authLogger3.middleware.error("Failed to update lastUsedAt", err));
|
|
12015
12351
|
c.set("auth", {
|
|
12016
12352
|
user,
|
|
12017
12353
|
userId: String(user.id),
|
|
@@ -12023,6 +12359,7 @@ var optionalAuth = defineMiddleware("optionalAuth", async (c, next) => {
|
|
|
12023
12359
|
} catch {
|
|
12024
12360
|
}
|
|
12025
12361
|
await next();
|
|
12362
|
+
return void 0;
|
|
12026
12363
|
}, { skips: ["auth"] });
|
|
12027
12364
|
|
|
12028
12365
|
// src/server/middleware/require-permission.ts
|
|
@@ -12487,7 +12824,7 @@ var userRouter = defineRouter3({
|
|
|
12487
12824
|
// src/server/routes/oauth/index.ts
|
|
12488
12825
|
init_esm();
|
|
12489
12826
|
|
|
12490
|
-
// ../../node_modules/.pnpm/hono@4.
|
|
12827
|
+
// ../../node_modules/.pnpm/hono@4.13.0/node_modules/hono/dist/utils/url.js
|
|
12491
12828
|
var tryDecode = (str, decoder) => {
|
|
12492
12829
|
try {
|
|
12493
12830
|
return decoder(str);
|
|
@@ -12501,10 +12838,12 @@ var tryDecode = (str, decoder) => {
|
|
|
12501
12838
|
});
|
|
12502
12839
|
}
|
|
12503
12840
|
};
|
|
12841
|
+
var tryDecodeURIComponent = (str) => str.indexOf("%") !== -1 ? tryDecode(str, decodeURIComponent_) : str;
|
|
12504
12842
|
var decodeURIComponent_ = decodeURIComponent;
|
|
12505
12843
|
|
|
12506
|
-
// ../../node_modules/.pnpm/hono@4.
|
|
12844
|
+
// ../../node_modules/.pnpm/hono@4.13.0/node_modules/hono/dist/utils/cookie.js
|
|
12507
12845
|
var validCookieNameRegEx = /^[\w!#$%&'*.^`|~+-]+$/;
|
|
12846
|
+
var relaxedCookieNameRegEx = /^[!#-:<>-[\]-~]+$/;
|
|
12508
12847
|
var validCookieValueRegEx = /^[ !#-:<-[\]-~]*$/;
|
|
12509
12848
|
var trimCookieWhitespace = (value) => {
|
|
12510
12849
|
let start = 0;
|
|
@@ -12537,7 +12876,7 @@ var parse = (cookie, name) => {
|
|
|
12537
12876
|
continue;
|
|
12538
12877
|
}
|
|
12539
12878
|
const cookieName = trimCookieWhitespace(pairStr.substring(0, valueStartPos));
|
|
12540
|
-
if (name && name !== cookieName || !
|
|
12879
|
+
if (name && name !== cookieName || !relaxedCookieNameRegEx.test(cookieName) || cookieName in parsedCookie) {
|
|
12541
12880
|
continue;
|
|
12542
12881
|
}
|
|
12543
12882
|
let cookieValue = trimCookieWhitespace(pairStr.substring(valueStartPos + 1));
|
|
@@ -12545,7 +12884,7 @@ var parse = (cookie, name) => {
|
|
|
12545
12884
|
cookieValue = cookieValue.slice(1, -1);
|
|
12546
12885
|
}
|
|
12547
12886
|
if (validCookieValueRegEx.test(cookieValue)) {
|
|
12548
|
-
parsedCookie[cookieName] =
|
|
12887
|
+
parsedCookie[cookieName] = tryDecodeURIComponent(cookieValue);
|
|
12549
12888
|
if (name) {
|
|
12550
12889
|
break;
|
|
12551
12890
|
}
|
|
@@ -12624,7 +12963,7 @@ var serialize = (name, value, opt) => {
|
|
|
12624
12963
|
return _serialize(name, value, opt);
|
|
12625
12964
|
};
|
|
12626
12965
|
|
|
12627
|
-
// ../../node_modules/.pnpm/hono@4.
|
|
12966
|
+
// ../../node_modules/.pnpm/hono@4.13.0/node_modules/hono/dist/helper/cookie/index.js
|
|
12628
12967
|
var getCookie = (c, key, prefix) => {
|
|
12629
12968
|
const cookie = c.req.raw.headers.get("Cookie");
|
|
12630
12969
|
if (typeof key === "string") {
|
|
@@ -13712,6 +14051,7 @@ export {
|
|
|
13712
14051
|
roles,
|
|
13713
14052
|
rolesRepository,
|
|
13714
14053
|
rotateKeyService,
|
|
14054
|
+
runAuthProfile,
|
|
13715
14055
|
runBeforeRegister,
|
|
13716
14056
|
sealSession,
|
|
13717
14057
|
selectAuthProfile,
|