@camstack/core 0.1.38 → 0.1.40
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/auth/auth-manager.d.ts +12 -1
- package/dist/auth/auth-manager.d.ts.map +1 -1
- package/dist/auth/scope-matcher.d.ts +8 -0
- package/dist/auth/scope-matcher.d.ts.map +1 -0
- package/dist/auth/totp-manager.d.ts +0 -1
- package/dist/auth/totp-manager.d.ts.map +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.d.ts +15 -0
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.d.ts.map +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +27 -6
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js.map +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +27 -6
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs.map +1 -1
- package/dist/builtins/device-manager/device-config-contribution.d.ts +33 -0
- package/dist/builtins/device-manager/device-config-contribution.d.ts.map +1 -0
- package/dist/builtins/device-manager/device-manager.addon.d.ts +52 -17
- package/dist/builtins/device-manager/device-manager.addon.d.ts.map +1 -1
- package/dist/builtins/device-manager/device-manager.addon.js +285 -161
- package/dist/builtins/device-manager/device-manager.addon.js.map +1 -1
- package/dist/builtins/device-manager/device-manager.addon.mjs +286 -162
- package/dist/builtins/device-manager/device-manager.addon.mjs.map +1 -1
- package/dist/builtins/local-auth/auth-schema.d.ts +1 -0
- package/dist/builtins/local-auth/auth-schema.d.ts.map +1 -1
- package/dist/builtins/local-auth/local-auth.addon.d.ts +1 -0
- package/dist/builtins/local-auth/local-auth.addon.d.ts.map +1 -1
- package/dist/builtins/local-auth/local-auth.addon.js +354 -3
- package/dist/builtins/local-auth/local-auth.addon.js.map +1 -1
- package/dist/builtins/local-auth/local-auth.addon.mjs +355 -3
- package/dist/builtins/local-auth/local-auth.addon.mjs.map +1 -1
- package/dist/builtins/local-auth/oauth-grants.d.ts +46 -0
- package/dist/builtins/local-auth/oauth-grants.d.ts.map +1 -0
- package/dist/builtins/local-auth/oauth-session-manager.d.ts +51 -0
- package/dist/builtins/local-auth/oauth-session-manager.d.ts.map +1 -0
- package/dist/builtins/remote-access-orchestrator/enabled-providers-reconcile.d.ts +97 -0
- package/dist/builtins/remote-access-orchestrator/enabled-providers-reconcile.d.ts.map +1 -0
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.d.ts +17 -0
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.d.ts.map +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +95 -5
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js.map +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +95 -5
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs.map +1 -1
- package/dist/builtins/snapshot/index.js +1 -3
- package/dist/builtins/snapshot/index.js.map +1 -1
- package/dist/builtins/snapshot/index.mjs +1 -3
- package/dist/builtins/snapshot/index.mjs.map +1 -1
- package/dist/builtins/snapshot/snapshot.addon.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +419 -97
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +419 -98
- package/dist/index.mjs.map +1 -1
- package/package.json +19 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { i as __toESM, r as __require, t as __commonJSMin } from "../../chunk-hT5z_Zn9.mjs";
|
|
2
2
|
import * as crypto$1 from "node:crypto";
|
|
3
|
+
import { randomUUID } from "node:crypto";
|
|
3
4
|
import { ApiKeyRecordSchema, BaseAddon, ScopedTokenSchema, UserRecordSchema, authProviderCapability, userManagementCapability } from "@camstack/types";
|
|
4
5
|
//#region ../../node_modules/safe-buffer/index.js
|
|
5
6
|
var require_safe_buffer = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
@@ -6238,7 +6239,12 @@ var AuthManager = class {
|
|
|
6238
6239
|
provider: payload.provider,
|
|
6239
6240
|
...payload.email !== void 0 ? { email: payload.email } : {},
|
|
6240
6241
|
...payload.displayName !== void 0 ? { displayName: payload.displayName } : {},
|
|
6241
|
-
...payload.hubUrl !== void 0 ? { hubUrl: payload.hubUrl } : {}
|
|
6242
|
+
...payload.hubUrl !== void 0 ? { hubUrl: payload.hubUrl } : {},
|
|
6243
|
+
...payload.scopes !== void 0 ? { scopes: payload.scopes } : {},
|
|
6244
|
+
...payload.redirectUri !== void 0 ? { redirectUri: payload.redirectUri } : {},
|
|
6245
|
+
...payload.integrationId !== void 0 ? { integrationId: payload.integrationId } : {},
|
|
6246
|
+
...payload.jti !== void 0 ? { jti: payload.jti } : {},
|
|
6247
|
+
...payload.sessionId !== void 0 ? { sessionId: payload.sessionId } : {}
|
|
6242
6248
|
};
|
|
6243
6249
|
return import_jsonwebtoken.sign(body, this.jwtSecret, { expiresIn: ttlSec });
|
|
6244
6250
|
}
|
|
@@ -6260,6 +6266,11 @@ var AuthManager = class {
|
|
|
6260
6266
|
const email = typeof decoded["email"] === "string" ? decoded["email"] : void 0;
|
|
6261
6267
|
const displayName = typeof decoded["displayName"] === "string" ? decoded["displayName"] : void 0;
|
|
6262
6268
|
const hubUrl = typeof decoded["hubUrl"] === "string" ? decoded["hubUrl"] : void 0;
|
|
6269
|
+
const scopes = Array.isArray(decoded["scopes"]) ? decoded["scopes"] : void 0;
|
|
6270
|
+
const redirectUri = typeof decoded["redirectUri"] === "string" ? decoded["redirectUri"] : void 0;
|
|
6271
|
+
const integrationId = typeof decoded["integrationId"] === "string" ? decoded["integrationId"] : void 0;
|
|
6272
|
+
const jti = typeof decoded["jti"] === "string" ? decoded["jti"] : void 0;
|
|
6273
|
+
const sessionId = typeof decoded["sessionId"] === "string" ? decoded["sessionId"] : void 0;
|
|
6263
6274
|
return {
|
|
6264
6275
|
userId,
|
|
6265
6276
|
username,
|
|
@@ -6267,7 +6278,12 @@ var AuthManager = class {
|
|
|
6267
6278
|
provider,
|
|
6268
6279
|
...email !== void 0 ? { email } : {},
|
|
6269
6280
|
...displayName !== void 0 ? { displayName } : {},
|
|
6270
|
-
...hubUrl !== void 0 ? { hubUrl } : {}
|
|
6281
|
+
...hubUrl !== void 0 ? { hubUrl } : {},
|
|
6282
|
+
...scopes !== void 0 ? { scopes } : {},
|
|
6283
|
+
...redirectUri !== void 0 ? { redirectUri } : {},
|
|
6284
|
+
...integrationId !== void 0 ? { integrationId } : {},
|
|
6285
|
+
...jti !== void 0 ? { jti } : {},
|
|
6286
|
+
...sessionId !== void 0 ? { sessionId } : {}
|
|
6271
6287
|
};
|
|
6272
6288
|
} catch {
|
|
6273
6289
|
return null;
|
|
@@ -6664,6 +6680,138 @@ var ScopedTokenManager = class {
|
|
|
6664
6680
|
}
|
|
6665
6681
|
};
|
|
6666
6682
|
//#endregion
|
|
6683
|
+
//#region src/builtins/local-auth/oauth-session-manager.ts
|
|
6684
|
+
/**
|
|
6685
|
+
* Manages OAuth session records in the `oauth_sessions` collection.
|
|
6686
|
+
*
|
|
6687
|
+
* Each record represents one Alexa-style account link. Sessions can be
|
|
6688
|
+
* active (`revokedAt = null`) or revoked (`revokedAt = <unix-ms>`).
|
|
6689
|
+
* `list()` returns both — callers decide whether to filter.
|
|
6690
|
+
*
|
|
6691
|
+
* Mirrors the pattern of `ScopedTokenManager`: takes a `SettingsStoreClient`
|
|
6692
|
+
* in its constructor and performs all reads/writes via the store's
|
|
6693
|
+
* `insert`, `update`, `delete`, and `query` primitives.
|
|
6694
|
+
*/
|
|
6695
|
+
var SESSIONS_COLLECTION = "oauth_sessions";
|
|
6696
|
+
function parseSession(data) {
|
|
6697
|
+
const id = data["id"];
|
|
6698
|
+
const userId = data["userId"];
|
|
6699
|
+
const username = data["username"];
|
|
6700
|
+
const integrationId = data["integrationId"];
|
|
6701
|
+
const scopes = data["scopes"];
|
|
6702
|
+
const createdAt = data["createdAt"];
|
|
6703
|
+
const lastUsedAt = data["lastUsedAt"];
|
|
6704
|
+
const revokedAt = data["revokedAt"];
|
|
6705
|
+
if (typeof id !== "string") throw new Error("oauth_sessions row: missing id");
|
|
6706
|
+
if (typeof userId !== "string") throw new Error("oauth_sessions row: missing userId");
|
|
6707
|
+
if (typeof username !== "string") throw new Error("oauth_sessions row: missing username");
|
|
6708
|
+
if (typeof integrationId !== "string") throw new Error("oauth_sessions row: missing integrationId");
|
|
6709
|
+
if (!Array.isArray(scopes)) throw new Error("oauth_sessions row: scopes must be an array");
|
|
6710
|
+
if (typeof createdAt !== "number") throw new Error("oauth_sessions row: missing createdAt");
|
|
6711
|
+
if (typeof lastUsedAt !== "number") throw new Error("oauth_sessions row: missing lastUsedAt");
|
|
6712
|
+
return {
|
|
6713
|
+
id,
|
|
6714
|
+
userId,
|
|
6715
|
+
username,
|
|
6716
|
+
integrationId,
|
|
6717
|
+
scopes,
|
|
6718
|
+
createdAt,
|
|
6719
|
+
lastUsedAt,
|
|
6720
|
+
revokedAt: typeof revokedAt === "number" ? revokedAt : null
|
|
6721
|
+
};
|
|
6722
|
+
}
|
|
6723
|
+
var OauthSessionManager = class {
|
|
6724
|
+
constructor(store) {
|
|
6725
|
+
this.store = store;
|
|
6726
|
+
}
|
|
6727
|
+
/**
|
|
6728
|
+
* Create a new OAuth session record. Generates a UUID as the session id,
|
|
6729
|
+
* sets `createdAt` and `lastUsedAt` to now, `revokedAt` to null.
|
|
6730
|
+
*/
|
|
6731
|
+
async create(input) {
|
|
6732
|
+
const now = Date.now();
|
|
6733
|
+
const session = {
|
|
6734
|
+
id: crypto$1.randomUUID(),
|
|
6735
|
+
userId: input.userId,
|
|
6736
|
+
username: input.username,
|
|
6737
|
+
integrationId: input.integrationId,
|
|
6738
|
+
scopes: input.scopes.map((s) => ({ ...s })),
|
|
6739
|
+
createdAt: now,
|
|
6740
|
+
lastUsedAt: now,
|
|
6741
|
+
revokedAt: null
|
|
6742
|
+
};
|
|
6743
|
+
await this.store.insert.mutate({
|
|
6744
|
+
collection: SESSIONS_COLLECTION,
|
|
6745
|
+
record: {
|
|
6746
|
+
id: session.id,
|
|
6747
|
+
data: { ...session }
|
|
6748
|
+
}
|
|
6749
|
+
});
|
|
6750
|
+
return session;
|
|
6751
|
+
}
|
|
6752
|
+
/**
|
|
6753
|
+
* Return all sessions — both active and revoked. Callers decide
|
|
6754
|
+
* whether to filter by `revokedAt`.
|
|
6755
|
+
*/
|
|
6756
|
+
async list() {
|
|
6757
|
+
return (await this.store.query.query({
|
|
6758
|
+
collection: SESSIONS_COLLECTION,
|
|
6759
|
+
filter: {}
|
|
6760
|
+
})).map((r) => parseSession(r.data));
|
|
6761
|
+
}
|
|
6762
|
+
/**
|
|
6763
|
+
* Look up a session by its id. Returns null when not found.
|
|
6764
|
+
*/
|
|
6765
|
+
async getById(id) {
|
|
6766
|
+
const results = await this.store.query.query({
|
|
6767
|
+
collection: SESSIONS_COLLECTION,
|
|
6768
|
+
filter: { where: { id } }
|
|
6769
|
+
});
|
|
6770
|
+
if (results.length === 0) return null;
|
|
6771
|
+
return parseSession(results[0].data);
|
|
6772
|
+
}
|
|
6773
|
+
/**
|
|
6774
|
+
* Mark a session as revoked by setting `revokedAt = now`.
|
|
6775
|
+
*
|
|
6776
|
+
* - Returns `true` on success (including idempotent re-revoke — the
|
|
6777
|
+
* existing `revokedAt` timestamp is preserved; it is NOT updated).
|
|
6778
|
+
* - Returns `false` when the session id is not found.
|
|
6779
|
+
*/
|
|
6780
|
+
async markRevoked(id) {
|
|
6781
|
+
const existing = await this.getById(id);
|
|
6782
|
+
if (existing === null) return false;
|
|
6783
|
+
if (existing.revokedAt !== null) return true;
|
|
6784
|
+
const updated = {
|
|
6785
|
+
...existing,
|
|
6786
|
+
revokedAt: Date.now()
|
|
6787
|
+
};
|
|
6788
|
+
await this.store.update.mutate({
|
|
6789
|
+
collection: SESSIONS_COLLECTION,
|
|
6790
|
+
id,
|
|
6791
|
+
data: { ...updated }
|
|
6792
|
+
});
|
|
6793
|
+
return true;
|
|
6794
|
+
}
|
|
6795
|
+
/**
|
|
6796
|
+
* Update `lastUsedAt` to now. No-op (does not throw) when the session
|
|
6797
|
+
* id is not found — the caller (token-use hot path) should not fail
|
|
6798
|
+
* for a missing session that may have been concurrently revoked.
|
|
6799
|
+
*/
|
|
6800
|
+
async touch(id) {
|
|
6801
|
+
const existing = await this.getById(id);
|
|
6802
|
+
if (existing === null) return;
|
|
6803
|
+
const updated = {
|
|
6804
|
+
...existing,
|
|
6805
|
+
lastUsedAt: Date.now()
|
|
6806
|
+
};
|
|
6807
|
+
await this.store.update.mutate({
|
|
6808
|
+
collection: SESSIONS_COLLECTION,
|
|
6809
|
+
id,
|
|
6810
|
+
data: { ...updated }
|
|
6811
|
+
});
|
|
6812
|
+
}
|
|
6813
|
+
};
|
|
6814
|
+
//#endregion
|
|
6667
6815
|
//#region ../../node_modules/@otplib/plugin-crypto/index.js
|
|
6668
6816
|
/**
|
|
6669
6817
|
* @otplib/plugin-crypto
|
|
@@ -7374,7 +7522,6 @@ function parseRow(data) {
|
|
|
7374
7522
|
var TotpManager = class {
|
|
7375
7523
|
constructor(store, opts = {}) {
|
|
7376
7524
|
this.store = store;
|
|
7377
|
-
this.opts = opts;
|
|
7378
7525
|
import_otplib.authenticator.options = { window: opts.window ?? 1 };
|
|
7379
7526
|
}
|
|
7380
7527
|
/**
|
|
@@ -7485,6 +7632,7 @@ var TotpManager = class {
|
|
|
7485
7632
|
var USERS_COLLECTION = "users";
|
|
7486
7633
|
var API_KEYS_COLLECTION = "api_keys";
|
|
7487
7634
|
var SCOPED_TOKENS_COLLECTION = "scoped_tokens";
|
|
7635
|
+
var OAUTH_SESSIONS_COLLECTION = "oauth_sessions";
|
|
7488
7636
|
/**
|
|
7489
7637
|
* TOTP enrollment table — split off from `users` to avoid the
|
|
7490
7638
|
* destructive drop-+-recreate migration `ensureTable` performs when a
|
|
@@ -7659,6 +7807,47 @@ var SCOPED_TOKENS_COLUMNS = [
|
|
|
7659
7807
|
notNull: true
|
|
7660
7808
|
}
|
|
7661
7809
|
];
|
|
7810
|
+
var OAUTH_SESSIONS_COLUMNS = [
|
|
7811
|
+
{
|
|
7812
|
+
name: "id",
|
|
7813
|
+
type: "TEXT",
|
|
7814
|
+
primaryKey: true,
|
|
7815
|
+
notNull: true
|
|
7816
|
+
},
|
|
7817
|
+
{
|
|
7818
|
+
name: "userId",
|
|
7819
|
+
type: "TEXT",
|
|
7820
|
+
notNull: true
|
|
7821
|
+
},
|
|
7822
|
+
{
|
|
7823
|
+
name: "username",
|
|
7824
|
+
type: "TEXT",
|
|
7825
|
+
notNull: true
|
|
7826
|
+
},
|
|
7827
|
+
{
|
|
7828
|
+
name: "integrationId",
|
|
7829
|
+
type: "TEXT",
|
|
7830
|
+
notNull: true
|
|
7831
|
+
},
|
|
7832
|
+
{
|
|
7833
|
+
name: "scopes",
|
|
7834
|
+
type: "JSON"
|
|
7835
|
+
},
|
|
7836
|
+
{
|
|
7837
|
+
name: "createdAt",
|
|
7838
|
+
type: "INTEGER",
|
|
7839
|
+
notNull: true
|
|
7840
|
+
},
|
|
7841
|
+
{
|
|
7842
|
+
name: "lastUsedAt",
|
|
7843
|
+
type: "INTEGER",
|
|
7844
|
+
notNull: true
|
|
7845
|
+
},
|
|
7846
|
+
{
|
|
7847
|
+
name: "revokedAt",
|
|
7848
|
+
type: "INTEGER"
|
|
7849
|
+
}
|
|
7850
|
+
];
|
|
7662
7851
|
/**
|
|
7663
7852
|
* Declare every auth collection with the typed schema. Called by
|
|
7664
7853
|
* `LocalAuthAddon.onInitialize` before constructing the per-collection
|
|
@@ -7690,6 +7879,124 @@ async function declareAuthSchema(store) {
|
|
|
7690
7879
|
collection: USER_TOTP_COLLECTION,
|
|
7691
7880
|
columns: USER_TOTP_COLUMNS
|
|
7692
7881
|
});
|
|
7882
|
+
await store.declareCollection.mutate({
|
|
7883
|
+
collection: OAUTH_SESSIONS_COLLECTION,
|
|
7884
|
+
columns: OAUTH_SESSIONS_COLUMNS,
|
|
7885
|
+
indexes: [{
|
|
7886
|
+
name: "idx_oauth_sessions_user_id",
|
|
7887
|
+
columns: ["userId"]
|
|
7888
|
+
}]
|
|
7889
|
+
});
|
|
7890
|
+
}
|
|
7891
|
+
//#endregion
|
|
7892
|
+
//#region src/builtins/local-auth/oauth-grants.ts
|
|
7893
|
+
var TTL = {
|
|
7894
|
+
"oauth-code": 60,
|
|
7895
|
+
"oauth-access": 3600,
|
|
7896
|
+
"oauth-refresh": 2592e3
|
|
7897
|
+
};
|
|
7898
|
+
/** OAuth account-linking grant logic. Pure over an injected sso-bridge
|
|
7899
|
+
* signer so it is unit-testable without the capability registry.
|
|
7900
|
+
*
|
|
7901
|
+
* Authorization codes are short-lived (60 s). The `redirectUri`,
|
|
7902
|
+
* `integrationId`, and a unique `jti` are embedded in the signed JWT
|
|
7903
|
+
* so the HMAC signature is the real security boundary. Single-use is
|
|
7904
|
+
* enforced by a `jti` consumed-set. The old in-process `pendingCodes`
|
|
7905
|
+
* Map is gone — a hub restart no longer breaks in-flight exchanges,
|
|
7906
|
+
* only risking a single replay within the remaining 60 s TTL. */
|
|
7907
|
+
function createOauthGrants(ssoBridge, sessionManager) {
|
|
7908
|
+
const consumedJtis = /* @__PURE__ */ new Map();
|
|
7909
|
+
const baseClaims = (userId, username, scopes, hubUrl) => ({
|
|
7910
|
+
userId,
|
|
7911
|
+
username,
|
|
7912
|
+
isAdmin: false,
|
|
7913
|
+
scopes,
|
|
7914
|
+
hubUrl
|
|
7915
|
+
});
|
|
7916
|
+
async function mintPair(userId, username, scopes, hubUrl, sessionId) {
|
|
7917
|
+
const access = await ssoBridge.signBridgeToken({
|
|
7918
|
+
claims: {
|
|
7919
|
+
...baseClaims(userId, username, scopes, hubUrl),
|
|
7920
|
+
provider: "oauth-access",
|
|
7921
|
+
sessionId
|
|
7922
|
+
},
|
|
7923
|
+
ttlSec: TTL["oauth-access"]
|
|
7924
|
+
});
|
|
7925
|
+
const refresh = await ssoBridge.signBridgeToken({
|
|
7926
|
+
claims: {
|
|
7927
|
+
...baseClaims(userId, username, scopes, hubUrl),
|
|
7928
|
+
provider: "oauth-refresh",
|
|
7929
|
+
sessionId
|
|
7930
|
+
},
|
|
7931
|
+
ttlSec: TTL["oauth-refresh"]
|
|
7932
|
+
});
|
|
7933
|
+
return {
|
|
7934
|
+
accessToken: access.token,
|
|
7935
|
+
refreshToken: refresh.token,
|
|
7936
|
+
expiresIn: TTL["oauth-access"]
|
|
7937
|
+
};
|
|
7938
|
+
}
|
|
7939
|
+
return {
|
|
7940
|
+
async oauthIssueCode(input) {
|
|
7941
|
+
const jti = randomUUID();
|
|
7942
|
+
const { token } = await ssoBridge.signBridgeToken({
|
|
7943
|
+
claims: {
|
|
7944
|
+
...baseClaims(input.userId, input.username, input.scopes, input.hubUrl),
|
|
7945
|
+
provider: "oauth-code",
|
|
7946
|
+
redirectUri: input.redirectUri,
|
|
7947
|
+
integrationId: input.integrationId,
|
|
7948
|
+
jti
|
|
7949
|
+
},
|
|
7950
|
+
ttlSec: TTL["oauth-code"]
|
|
7951
|
+
});
|
|
7952
|
+
return { code: token };
|
|
7953
|
+
},
|
|
7954
|
+
async oauthExchangeCode(input) {
|
|
7955
|
+
const claims = await ssoBridge.verifyBridgeToken({ token: input.code });
|
|
7956
|
+
if (!claims || claims.provider !== "oauth-code") return null;
|
|
7957
|
+
if (claims.redirectUri !== input.redirectUri) return null;
|
|
7958
|
+
const jti = claims.jti;
|
|
7959
|
+
if (!jti) return null;
|
|
7960
|
+
const expiryMs = Date.now() + TTL["oauth-code"] * 1e3;
|
|
7961
|
+
if (consumedJtis.has(jti)) return null;
|
|
7962
|
+
consumedJtis.set(jti, expiryMs);
|
|
7963
|
+
setTimeout(() => {
|
|
7964
|
+
consumedJtis.delete(jti);
|
|
7965
|
+
}, TTL["oauth-code"] * 1e3).unref?.();
|
|
7966
|
+
const scopes = claims.scopes ?? [];
|
|
7967
|
+
const session = await sessionManager.create({
|
|
7968
|
+
userId: claims.userId,
|
|
7969
|
+
username: claims.username,
|
|
7970
|
+
integrationId: typeof claims.integrationId === "string" ? claims.integrationId : "<unknown>",
|
|
7971
|
+
scopes
|
|
7972
|
+
});
|
|
7973
|
+
return mintPair(claims.userId, claims.username, scopes, claims.hubUrl ?? "", session.id);
|
|
7974
|
+
},
|
|
7975
|
+
async oauthRefresh(input) {
|
|
7976
|
+
const claims = await ssoBridge.verifyBridgeToken({ token: input.refreshToken });
|
|
7977
|
+
if (!claims || claims.provider !== "oauth-refresh") return null;
|
|
7978
|
+
const sessionId = typeof claims.sessionId === "string" ? claims.sessionId : null;
|
|
7979
|
+
if (!sessionId) return null;
|
|
7980
|
+
const session = await sessionManager.getById(sessionId);
|
|
7981
|
+
if (!session || session.revokedAt != null) return null;
|
|
7982
|
+
await sessionManager.touch(sessionId);
|
|
7983
|
+
const scopes = claims.scopes ?? [];
|
|
7984
|
+
return mintPair(claims.userId, claims.username, scopes, claims.hubUrl ?? "", sessionId);
|
|
7985
|
+
},
|
|
7986
|
+
async oauthVerifyAccessToken(input) {
|
|
7987
|
+
const claims = await ssoBridge.verifyBridgeToken({ token: input.token });
|
|
7988
|
+
if (!claims || claims.provider !== "oauth-access") return null;
|
|
7989
|
+
const sessionId = typeof claims.sessionId === "string" ? claims.sessionId : null;
|
|
7990
|
+
if (!sessionId) return null;
|
|
7991
|
+
const session = await sessionManager.getById(sessionId);
|
|
7992
|
+
if (!session || session.revokedAt != null) return null;
|
|
7993
|
+
return {
|
|
7994
|
+
userId: claims.userId,
|
|
7995
|
+
username: claims.username,
|
|
7996
|
+
scopes: claims.scopes ?? []
|
|
7997
|
+
};
|
|
7998
|
+
}
|
|
7999
|
+
};
|
|
7693
8000
|
}
|
|
7694
8001
|
//#endregion
|
|
7695
8002
|
//#region src/builtins/local-auth/local-auth.addon.ts
|
|
@@ -7706,6 +8013,7 @@ var LocalAuthAddon = class extends BaseAddon {
|
|
|
7706
8013
|
userManager = null;
|
|
7707
8014
|
apiKeyManager = null;
|
|
7708
8015
|
scopedTokenManager = null;
|
|
8016
|
+
oauthSessionManager = null;
|
|
7709
8017
|
totpManager = null;
|
|
7710
8018
|
constructor() {
|
|
7711
8019
|
super({
|
|
@@ -7739,6 +8047,7 @@ var LocalAuthAddon = class extends BaseAddon {
|
|
|
7739
8047
|
this.userManager = new UserManager(storageAccess, this.authManager, reader);
|
|
7740
8048
|
this.apiKeyManager = new ApiKeyManager(storageAccess, this.authManager);
|
|
7741
8049
|
this.scopedTokenManager = new ScopedTokenManager(store);
|
|
8050
|
+
this.oauthSessionManager = new OauthSessionManager(store);
|
|
7742
8051
|
this.totpManager = new TotpManager(store);
|
|
7743
8052
|
try {
|
|
7744
8053
|
await this.userManager.ensureAdminExists();
|
|
@@ -7775,6 +8084,19 @@ var LocalAuthAddon = class extends BaseAddon {
|
|
|
7775
8084
|
}
|
|
7776
8085
|
}
|
|
7777
8086
|
};
|
|
8087
|
+
let cachedOauthGrants = null;
|
|
8088
|
+
const lazyOauthGrants = () => {
|
|
8089
|
+
if (cachedOauthGrants) return cachedOauthGrants;
|
|
8090
|
+
const bridgeApi = this.ctx.api?.ssoBridge;
|
|
8091
|
+
if (!bridgeApi) throw new Error("local-auth: sso-bridge capability not available via ctx.api — hub boot incomplete");
|
|
8092
|
+
const ssoBridgeProvider = {
|
|
8093
|
+
signBridgeToken: (input) => bridgeApi.signBridgeToken.query(input),
|
|
8094
|
+
verifyBridgeToken: (input) => bridgeApi.verifyBridgeToken.query(input)
|
|
8095
|
+
};
|
|
8096
|
+
if (!this.oauthSessionManager) throw new Error("local-auth: oauthSessionManager not initialized — hub boot incomplete");
|
|
8097
|
+
cachedOauthGrants = createOauthGrants(ssoBridgeProvider, this.oauthSessionManager);
|
|
8098
|
+
return cachedOauthGrants;
|
|
8099
|
+
};
|
|
7778
8100
|
const userMgmt = {
|
|
7779
8101
|
listUsers: async () => {
|
|
7780
8102
|
if (!this.userManager) return [];
|
|
@@ -7874,6 +8196,35 @@ var LocalAuthAddon = class extends BaseAddon {
|
|
|
7874
8196
|
if (!this.scopedTokenManager) return [];
|
|
7875
8197
|
return this.scopedTokenManager.listForUser(input.userId);
|
|
7876
8198
|
},
|
|
8199
|
+
oauthIssueCode: async (input) => {
|
|
8200
|
+
return lazyOauthGrants().oauthIssueCode(input);
|
|
8201
|
+
},
|
|
8202
|
+
oauthExchangeCode: async (input) => {
|
|
8203
|
+
return lazyOauthGrants().oauthExchangeCode(input);
|
|
8204
|
+
},
|
|
8205
|
+
oauthRefresh: async (input) => {
|
|
8206
|
+
return lazyOauthGrants().oauthRefresh(input);
|
|
8207
|
+
},
|
|
8208
|
+
oauthVerifyAccessToken: async (input) => {
|
|
8209
|
+
return lazyOauthGrants().oauthVerifyAccessToken(input);
|
|
8210
|
+
},
|
|
8211
|
+
listOauthSessions: async () => {
|
|
8212
|
+
if (!this.oauthSessionManager) return [];
|
|
8213
|
+
return (await this.oauthSessionManager.list()).map((s) => ({
|
|
8214
|
+
id: s.id,
|
|
8215
|
+
userId: s.userId,
|
|
8216
|
+
username: s.username,
|
|
8217
|
+
integrationId: s.integrationId,
|
|
8218
|
+
scopes: s.scopes,
|
|
8219
|
+
createdAt: s.createdAt,
|
|
8220
|
+
lastUsedAt: s.lastUsedAt,
|
|
8221
|
+
revokedAt: s.revokedAt
|
|
8222
|
+
}));
|
|
8223
|
+
},
|
|
8224
|
+
revokeOauthSession: async (input) => {
|
|
8225
|
+
if (!this.oauthSessionManager) return { success: false };
|
|
8226
|
+
return { success: await this.oauthSessionManager.markRevoked(input.id) };
|
|
8227
|
+
},
|
|
7877
8228
|
setupTotp: async (input) => {
|
|
7878
8229
|
if (!this.totpManager || !this.userManager) throw new Error("TOTP management not available");
|
|
7879
8230
|
const user = await this.userManager.findById(input.userId);
|
|
@@ -7916,6 +8267,7 @@ var LocalAuthAddon = class extends BaseAddon {
|
|
|
7916
8267
|
this.userManager = null;
|
|
7917
8268
|
this.apiKeyManager = null;
|
|
7918
8269
|
this.scopedTokenManager = null;
|
|
8270
|
+
this.oauthSessionManager = null;
|
|
7919
8271
|
}
|
|
7920
8272
|
};
|
|
7921
8273
|
//#endregion
|