@camstack/core 0.1.37 → 0.1.39
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 +24 -1
- 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 +136 -56
- 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 +137 -57
- 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 +428 -234
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +428 -235
- package/dist/index.mjs.map +1 -1
- package/package.json +19 -37
- package/dist/builtins/auth-orchestrator/auth-orchestrator.addon.d.ts +0 -8
- package/dist/builtins/auth-orchestrator/auth-orchestrator.addon.d.ts.map +0 -1
- package/dist/builtins/auth-orchestrator/auth-orchestrator.addon.js +0 -75
- package/dist/builtins/auth-orchestrator/auth-orchestrator.addon.js.map +0 -1
- package/dist/builtins/auth-orchestrator/auth-orchestrator.addon.mjs +0 -69
- package/dist/builtins/auth-orchestrator/auth-orchestrator.addon.mjs.map +0 -1
- package/dist/builtins/auth-orchestrator/index.d.ts +0 -2
- package/dist/builtins/auth-orchestrator/index.d.ts.map +0 -1
- package/dist/builtins/auth-orchestrator/index.js +0 -7
- package/dist/builtins/auth-orchestrator/index.mjs +0 -2
- package/dist/builtins/mesh-orchestrator/index.d.ts +0 -2
- package/dist/builtins/mesh-orchestrator/index.d.ts.map +0 -1
- package/dist/builtins/mesh-orchestrator/index.js +0 -7
- package/dist/builtins/mesh-orchestrator/index.mjs +0 -2
- package/dist/builtins/mesh-orchestrator/mesh-orchestrator.addon.d.ts +0 -9
- package/dist/builtins/mesh-orchestrator/mesh-orchestrator.addon.d.ts.map +0 -1
- package/dist/builtins/mesh-orchestrator/mesh-orchestrator.addon.js +0 -113
- package/dist/builtins/mesh-orchestrator/mesh-orchestrator.addon.js.map +0 -1
- package/dist/builtins/mesh-orchestrator/mesh-orchestrator.addon.mjs +0 -107
- package/dist/builtins/mesh-orchestrator/mesh-orchestrator.addon.mjs.map +0 -1
- package/dist/builtins/turn-orchestrator/index.d.ts +0 -2
- package/dist/builtins/turn-orchestrator/index.d.ts.map +0 -1
- package/dist/builtins/turn-orchestrator/index.js +0 -7
- package/dist/builtins/turn-orchestrator/index.mjs +0 -2
- package/dist/builtins/turn-orchestrator/turn-orchestrator.addon.d.ts +0 -34
- package/dist/builtins/turn-orchestrator/turn-orchestrator.addon.d.ts.map +0 -1
- package/dist/builtins/turn-orchestrator/turn-orchestrator.addon.js +0 -126
- package/dist/builtins/turn-orchestrator/turn-orchestrator.addon.js.map +0 -1
- package/dist/builtins/turn-orchestrator/turn-orchestrator.addon.mjs +0 -120
- package/dist/builtins/turn-orchestrator/turn-orchestrator.addon.mjs.map +0 -1
|
@@ -2,6 +2,7 @@ import { SettingsStoreClient } from '@camstack/types';
|
|
|
2
2
|
export declare const USERS_COLLECTION = "users";
|
|
3
3
|
export declare const API_KEYS_COLLECTION = "api_keys";
|
|
4
4
|
export declare const SCOPED_TOKENS_COLLECTION = "scoped_tokens";
|
|
5
|
+
export declare const OAUTH_SESSIONS_COLLECTION = "oauth_sessions";
|
|
5
6
|
/**
|
|
6
7
|
* TOTP enrollment table — split off from `users` to avoid the
|
|
7
8
|
* destructive drop-+-recreate migration `ensureTable` performs when a
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-schema.d.ts","sourceRoot":"","sources":["../../../src/builtins/local-auth/auth-schema.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"auth-schema.d.ts","sourceRoot":"","sources":["../../../src/builtins/local-auth/auth-schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAE1D,eAAO,MAAM,gBAAgB,UAAU,CAAA;AACvC,eAAO,MAAM,mBAAmB,aAAa,CAAA;AAC7C,eAAO,MAAM,wBAAwB,kBAAkB,CAAA;AACvD,eAAO,MAAM,yBAAyB,mBAAmB,CAAA;AACzD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,oBAAoB,cAAc,CAAA;AAoE/C;;;;;GAKG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CA8BjF"}
|
|
@@ -9,6 +9,7 @@ export declare class LocalAuthAddon extends BaseAddon<LocalAuthConfig> {
|
|
|
9
9
|
private userManager;
|
|
10
10
|
private apiKeyManager;
|
|
11
11
|
private scopedTokenManager;
|
|
12
|
+
private oauthSessionManager;
|
|
12
13
|
private totpManager;
|
|
13
14
|
constructor();
|
|
14
15
|
protected onInitialize(): Promise<ProviderRegistration[]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-auth.addon.d.ts","sourceRoot":"","sources":["../../../src/builtins/local-auth/local-auth.addon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"local-auth.addon.d.ts","sourceRoot":"","sources":["../../../src/builtins/local-auth/local-auth.addon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAA+C,oBAAoB,EAAE,MAAM,iBAAiB,CAAA;AACxG,OAAO,EAAE,SAAS,EAAoD,MAAM,iBAAiB,CAAA;AA+B7F,UAAU,eAAe;IACvB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,qBAAa,cAAe,SAAQ,SAAS,CAAC,eAAe,CAAC;IAC5D,OAAO,CAAC,WAAW,CAA2B;IAC9C,OAAO,CAAC,WAAW,CAA2B;IAC9C,OAAO,CAAC,aAAa,CAA6B;IAClD,OAAO,CAAC,kBAAkB,CAAkC;IAC5D,OAAO,CAAC,mBAAmB,CAAmC;IAC9D,OAAO,CAAC,WAAW,CAA2B;;cAI9B,YAAY,IAAI,OAAO,CAAC,oBAAoB,EAAE,CAAC;cA4U/C,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CAQ5C;AAED,eAAe,cAAc,CAAA"}
|
|
@@ -6243,7 +6243,12 @@ var AuthManager = class {
|
|
|
6243
6243
|
provider: payload.provider,
|
|
6244
6244
|
...payload.email !== void 0 ? { email: payload.email } : {},
|
|
6245
6245
|
...payload.displayName !== void 0 ? { displayName: payload.displayName } : {},
|
|
6246
|
-
...payload.hubUrl !== void 0 ? { hubUrl: payload.hubUrl } : {}
|
|
6246
|
+
...payload.hubUrl !== void 0 ? { hubUrl: payload.hubUrl } : {},
|
|
6247
|
+
...payload.scopes !== void 0 ? { scopes: payload.scopes } : {},
|
|
6248
|
+
...payload.redirectUri !== void 0 ? { redirectUri: payload.redirectUri } : {},
|
|
6249
|
+
...payload.integrationId !== void 0 ? { integrationId: payload.integrationId } : {},
|
|
6250
|
+
...payload.jti !== void 0 ? { jti: payload.jti } : {},
|
|
6251
|
+
...payload.sessionId !== void 0 ? { sessionId: payload.sessionId } : {}
|
|
6247
6252
|
};
|
|
6248
6253
|
return import_jsonwebtoken.sign(body, this.jwtSecret, { expiresIn: ttlSec });
|
|
6249
6254
|
}
|
|
@@ -6265,6 +6270,11 @@ var AuthManager = class {
|
|
|
6265
6270
|
const email = typeof decoded["email"] === "string" ? decoded["email"] : void 0;
|
|
6266
6271
|
const displayName = typeof decoded["displayName"] === "string" ? decoded["displayName"] : void 0;
|
|
6267
6272
|
const hubUrl = typeof decoded["hubUrl"] === "string" ? decoded["hubUrl"] : void 0;
|
|
6273
|
+
const scopes = Array.isArray(decoded["scopes"]) ? decoded["scopes"] : void 0;
|
|
6274
|
+
const redirectUri = typeof decoded["redirectUri"] === "string" ? decoded["redirectUri"] : void 0;
|
|
6275
|
+
const integrationId = typeof decoded["integrationId"] === "string" ? decoded["integrationId"] : void 0;
|
|
6276
|
+
const jti = typeof decoded["jti"] === "string" ? decoded["jti"] : void 0;
|
|
6277
|
+
const sessionId = typeof decoded["sessionId"] === "string" ? decoded["sessionId"] : void 0;
|
|
6268
6278
|
return {
|
|
6269
6279
|
userId,
|
|
6270
6280
|
username,
|
|
@@ -6272,7 +6282,12 @@ var AuthManager = class {
|
|
|
6272
6282
|
provider,
|
|
6273
6283
|
...email !== void 0 ? { email } : {},
|
|
6274
6284
|
...displayName !== void 0 ? { displayName } : {},
|
|
6275
|
-
...hubUrl !== void 0 ? { hubUrl } : {}
|
|
6285
|
+
...hubUrl !== void 0 ? { hubUrl } : {},
|
|
6286
|
+
...scopes !== void 0 ? { scopes } : {},
|
|
6287
|
+
...redirectUri !== void 0 ? { redirectUri } : {},
|
|
6288
|
+
...integrationId !== void 0 ? { integrationId } : {},
|
|
6289
|
+
...jti !== void 0 ? { jti } : {},
|
|
6290
|
+
...sessionId !== void 0 ? { sessionId } : {}
|
|
6276
6291
|
};
|
|
6277
6292
|
} catch {
|
|
6278
6293
|
return null;
|
|
@@ -6669,6 +6684,138 @@ var ScopedTokenManager = class {
|
|
|
6669
6684
|
}
|
|
6670
6685
|
};
|
|
6671
6686
|
//#endregion
|
|
6687
|
+
//#region src/builtins/local-auth/oauth-session-manager.ts
|
|
6688
|
+
/**
|
|
6689
|
+
* Manages OAuth session records in the `oauth_sessions` collection.
|
|
6690
|
+
*
|
|
6691
|
+
* Each record represents one Alexa-style account link. Sessions can be
|
|
6692
|
+
* active (`revokedAt = null`) or revoked (`revokedAt = <unix-ms>`).
|
|
6693
|
+
* `list()` returns both — callers decide whether to filter.
|
|
6694
|
+
*
|
|
6695
|
+
* Mirrors the pattern of `ScopedTokenManager`: takes a `SettingsStoreClient`
|
|
6696
|
+
* in its constructor and performs all reads/writes via the store's
|
|
6697
|
+
* `insert`, `update`, `delete`, and `query` primitives.
|
|
6698
|
+
*/
|
|
6699
|
+
var SESSIONS_COLLECTION = "oauth_sessions";
|
|
6700
|
+
function parseSession(data) {
|
|
6701
|
+
const id = data["id"];
|
|
6702
|
+
const userId = data["userId"];
|
|
6703
|
+
const username = data["username"];
|
|
6704
|
+
const integrationId = data["integrationId"];
|
|
6705
|
+
const scopes = data["scopes"];
|
|
6706
|
+
const createdAt = data["createdAt"];
|
|
6707
|
+
const lastUsedAt = data["lastUsedAt"];
|
|
6708
|
+
const revokedAt = data["revokedAt"];
|
|
6709
|
+
if (typeof id !== "string") throw new Error("oauth_sessions row: missing id");
|
|
6710
|
+
if (typeof userId !== "string") throw new Error("oauth_sessions row: missing userId");
|
|
6711
|
+
if (typeof username !== "string") throw new Error("oauth_sessions row: missing username");
|
|
6712
|
+
if (typeof integrationId !== "string") throw new Error("oauth_sessions row: missing integrationId");
|
|
6713
|
+
if (!Array.isArray(scopes)) throw new Error("oauth_sessions row: scopes must be an array");
|
|
6714
|
+
if (typeof createdAt !== "number") throw new Error("oauth_sessions row: missing createdAt");
|
|
6715
|
+
if (typeof lastUsedAt !== "number") throw new Error("oauth_sessions row: missing lastUsedAt");
|
|
6716
|
+
return {
|
|
6717
|
+
id,
|
|
6718
|
+
userId,
|
|
6719
|
+
username,
|
|
6720
|
+
integrationId,
|
|
6721
|
+
scopes,
|
|
6722
|
+
createdAt,
|
|
6723
|
+
lastUsedAt,
|
|
6724
|
+
revokedAt: typeof revokedAt === "number" ? revokedAt : null
|
|
6725
|
+
};
|
|
6726
|
+
}
|
|
6727
|
+
var OauthSessionManager = class {
|
|
6728
|
+
constructor(store) {
|
|
6729
|
+
this.store = store;
|
|
6730
|
+
}
|
|
6731
|
+
/**
|
|
6732
|
+
* Create a new OAuth session record. Generates a UUID as the session id,
|
|
6733
|
+
* sets `createdAt` and `lastUsedAt` to now, `revokedAt` to null.
|
|
6734
|
+
*/
|
|
6735
|
+
async create(input) {
|
|
6736
|
+
const now = Date.now();
|
|
6737
|
+
const session = {
|
|
6738
|
+
id: node_crypto.randomUUID(),
|
|
6739
|
+
userId: input.userId,
|
|
6740
|
+
username: input.username,
|
|
6741
|
+
integrationId: input.integrationId,
|
|
6742
|
+
scopes: input.scopes.map((s) => ({ ...s })),
|
|
6743
|
+
createdAt: now,
|
|
6744
|
+
lastUsedAt: now,
|
|
6745
|
+
revokedAt: null
|
|
6746
|
+
};
|
|
6747
|
+
await this.store.insert.mutate({
|
|
6748
|
+
collection: SESSIONS_COLLECTION,
|
|
6749
|
+
record: {
|
|
6750
|
+
id: session.id,
|
|
6751
|
+
data: { ...session }
|
|
6752
|
+
}
|
|
6753
|
+
});
|
|
6754
|
+
return session;
|
|
6755
|
+
}
|
|
6756
|
+
/**
|
|
6757
|
+
* Return all sessions — both active and revoked. Callers decide
|
|
6758
|
+
* whether to filter by `revokedAt`.
|
|
6759
|
+
*/
|
|
6760
|
+
async list() {
|
|
6761
|
+
return (await this.store.query.query({
|
|
6762
|
+
collection: SESSIONS_COLLECTION,
|
|
6763
|
+
filter: {}
|
|
6764
|
+
})).map((r) => parseSession(r.data));
|
|
6765
|
+
}
|
|
6766
|
+
/**
|
|
6767
|
+
* Look up a session by its id. Returns null when not found.
|
|
6768
|
+
*/
|
|
6769
|
+
async getById(id) {
|
|
6770
|
+
const results = await this.store.query.query({
|
|
6771
|
+
collection: SESSIONS_COLLECTION,
|
|
6772
|
+
filter: { where: { id } }
|
|
6773
|
+
});
|
|
6774
|
+
if (results.length === 0) return null;
|
|
6775
|
+
return parseSession(results[0].data);
|
|
6776
|
+
}
|
|
6777
|
+
/**
|
|
6778
|
+
* Mark a session as revoked by setting `revokedAt = now`.
|
|
6779
|
+
*
|
|
6780
|
+
* - Returns `true` on success (including idempotent re-revoke — the
|
|
6781
|
+
* existing `revokedAt` timestamp is preserved; it is NOT updated).
|
|
6782
|
+
* - Returns `false` when the session id is not found.
|
|
6783
|
+
*/
|
|
6784
|
+
async markRevoked(id) {
|
|
6785
|
+
const existing = await this.getById(id);
|
|
6786
|
+
if (existing === null) return false;
|
|
6787
|
+
if (existing.revokedAt !== null) return true;
|
|
6788
|
+
const updated = {
|
|
6789
|
+
...existing,
|
|
6790
|
+
revokedAt: Date.now()
|
|
6791
|
+
};
|
|
6792
|
+
await this.store.update.mutate({
|
|
6793
|
+
collection: SESSIONS_COLLECTION,
|
|
6794
|
+
id,
|
|
6795
|
+
data: { ...updated }
|
|
6796
|
+
});
|
|
6797
|
+
return true;
|
|
6798
|
+
}
|
|
6799
|
+
/**
|
|
6800
|
+
* Update `lastUsedAt` to now. No-op (does not throw) when the session
|
|
6801
|
+
* id is not found — the caller (token-use hot path) should not fail
|
|
6802
|
+
* for a missing session that may have been concurrently revoked.
|
|
6803
|
+
*/
|
|
6804
|
+
async touch(id) {
|
|
6805
|
+
const existing = await this.getById(id);
|
|
6806
|
+
if (existing === null) return;
|
|
6807
|
+
const updated = {
|
|
6808
|
+
...existing,
|
|
6809
|
+
lastUsedAt: Date.now()
|
|
6810
|
+
};
|
|
6811
|
+
await this.store.update.mutate({
|
|
6812
|
+
collection: SESSIONS_COLLECTION,
|
|
6813
|
+
id,
|
|
6814
|
+
data: { ...updated }
|
|
6815
|
+
});
|
|
6816
|
+
}
|
|
6817
|
+
};
|
|
6818
|
+
//#endregion
|
|
6672
6819
|
//#region ../../node_modules/@otplib/plugin-crypto/index.js
|
|
6673
6820
|
/**
|
|
6674
6821
|
* @otplib/plugin-crypto
|
|
@@ -7379,7 +7526,6 @@ function parseRow(data) {
|
|
|
7379
7526
|
var TotpManager = class {
|
|
7380
7527
|
constructor(store, opts = {}) {
|
|
7381
7528
|
this.store = store;
|
|
7382
|
-
this.opts = opts;
|
|
7383
7529
|
import_otplib.authenticator.options = { window: opts.window ?? 1 };
|
|
7384
7530
|
}
|
|
7385
7531
|
/**
|
|
@@ -7490,6 +7636,7 @@ var TotpManager = class {
|
|
|
7490
7636
|
var USERS_COLLECTION = "users";
|
|
7491
7637
|
var API_KEYS_COLLECTION = "api_keys";
|
|
7492
7638
|
var SCOPED_TOKENS_COLLECTION = "scoped_tokens";
|
|
7639
|
+
var OAUTH_SESSIONS_COLLECTION = "oauth_sessions";
|
|
7493
7640
|
/**
|
|
7494
7641
|
* TOTP enrollment table — split off from `users` to avoid the
|
|
7495
7642
|
* destructive drop-+-recreate migration `ensureTable` performs when a
|
|
@@ -7664,6 +7811,47 @@ var SCOPED_TOKENS_COLUMNS = [
|
|
|
7664
7811
|
notNull: true
|
|
7665
7812
|
}
|
|
7666
7813
|
];
|
|
7814
|
+
var OAUTH_SESSIONS_COLUMNS = [
|
|
7815
|
+
{
|
|
7816
|
+
name: "id",
|
|
7817
|
+
type: "TEXT",
|
|
7818
|
+
primaryKey: true,
|
|
7819
|
+
notNull: true
|
|
7820
|
+
},
|
|
7821
|
+
{
|
|
7822
|
+
name: "userId",
|
|
7823
|
+
type: "TEXT",
|
|
7824
|
+
notNull: true
|
|
7825
|
+
},
|
|
7826
|
+
{
|
|
7827
|
+
name: "username",
|
|
7828
|
+
type: "TEXT",
|
|
7829
|
+
notNull: true
|
|
7830
|
+
},
|
|
7831
|
+
{
|
|
7832
|
+
name: "integrationId",
|
|
7833
|
+
type: "TEXT",
|
|
7834
|
+
notNull: true
|
|
7835
|
+
},
|
|
7836
|
+
{
|
|
7837
|
+
name: "scopes",
|
|
7838
|
+
type: "JSON"
|
|
7839
|
+
},
|
|
7840
|
+
{
|
|
7841
|
+
name: "createdAt",
|
|
7842
|
+
type: "INTEGER",
|
|
7843
|
+
notNull: true
|
|
7844
|
+
},
|
|
7845
|
+
{
|
|
7846
|
+
name: "lastUsedAt",
|
|
7847
|
+
type: "INTEGER",
|
|
7848
|
+
notNull: true
|
|
7849
|
+
},
|
|
7850
|
+
{
|
|
7851
|
+
name: "revokedAt",
|
|
7852
|
+
type: "INTEGER"
|
|
7853
|
+
}
|
|
7854
|
+
];
|
|
7667
7855
|
/**
|
|
7668
7856
|
* Declare every auth collection with the typed schema. Called by
|
|
7669
7857
|
* `LocalAuthAddon.onInitialize` before constructing the per-collection
|
|
@@ -7695,6 +7883,124 @@ async function declareAuthSchema(store) {
|
|
|
7695
7883
|
collection: USER_TOTP_COLLECTION,
|
|
7696
7884
|
columns: USER_TOTP_COLUMNS
|
|
7697
7885
|
});
|
|
7886
|
+
await store.declareCollection.mutate({
|
|
7887
|
+
collection: OAUTH_SESSIONS_COLLECTION,
|
|
7888
|
+
columns: OAUTH_SESSIONS_COLUMNS,
|
|
7889
|
+
indexes: [{
|
|
7890
|
+
name: "idx_oauth_sessions_user_id",
|
|
7891
|
+
columns: ["userId"]
|
|
7892
|
+
}]
|
|
7893
|
+
});
|
|
7894
|
+
}
|
|
7895
|
+
//#endregion
|
|
7896
|
+
//#region src/builtins/local-auth/oauth-grants.ts
|
|
7897
|
+
var TTL = {
|
|
7898
|
+
"oauth-code": 60,
|
|
7899
|
+
"oauth-access": 3600,
|
|
7900
|
+
"oauth-refresh": 2592e3
|
|
7901
|
+
};
|
|
7902
|
+
/** OAuth account-linking grant logic. Pure over an injected sso-bridge
|
|
7903
|
+
* signer so it is unit-testable without the capability registry.
|
|
7904
|
+
*
|
|
7905
|
+
* Authorization codes are short-lived (60 s). The `redirectUri`,
|
|
7906
|
+
* `integrationId`, and a unique `jti` are embedded in the signed JWT
|
|
7907
|
+
* so the HMAC signature is the real security boundary. Single-use is
|
|
7908
|
+
* enforced by a `jti` consumed-set. The old in-process `pendingCodes`
|
|
7909
|
+
* Map is gone — a hub restart no longer breaks in-flight exchanges,
|
|
7910
|
+
* only risking a single replay within the remaining 60 s TTL. */
|
|
7911
|
+
function createOauthGrants(ssoBridge, sessionManager) {
|
|
7912
|
+
const consumedJtis = /* @__PURE__ */ new Map();
|
|
7913
|
+
const baseClaims = (userId, username, scopes, hubUrl) => ({
|
|
7914
|
+
userId,
|
|
7915
|
+
username,
|
|
7916
|
+
isAdmin: false,
|
|
7917
|
+
scopes,
|
|
7918
|
+
hubUrl
|
|
7919
|
+
});
|
|
7920
|
+
async function mintPair(userId, username, scopes, hubUrl, sessionId) {
|
|
7921
|
+
const access = await ssoBridge.signBridgeToken({
|
|
7922
|
+
claims: {
|
|
7923
|
+
...baseClaims(userId, username, scopes, hubUrl),
|
|
7924
|
+
provider: "oauth-access",
|
|
7925
|
+
sessionId
|
|
7926
|
+
},
|
|
7927
|
+
ttlSec: TTL["oauth-access"]
|
|
7928
|
+
});
|
|
7929
|
+
const refresh = await ssoBridge.signBridgeToken({
|
|
7930
|
+
claims: {
|
|
7931
|
+
...baseClaims(userId, username, scopes, hubUrl),
|
|
7932
|
+
provider: "oauth-refresh",
|
|
7933
|
+
sessionId
|
|
7934
|
+
},
|
|
7935
|
+
ttlSec: TTL["oauth-refresh"]
|
|
7936
|
+
});
|
|
7937
|
+
return {
|
|
7938
|
+
accessToken: access.token,
|
|
7939
|
+
refreshToken: refresh.token,
|
|
7940
|
+
expiresIn: TTL["oauth-access"]
|
|
7941
|
+
};
|
|
7942
|
+
}
|
|
7943
|
+
return {
|
|
7944
|
+
async oauthIssueCode(input) {
|
|
7945
|
+
const jti = (0, node_crypto.randomUUID)();
|
|
7946
|
+
const { token } = await ssoBridge.signBridgeToken({
|
|
7947
|
+
claims: {
|
|
7948
|
+
...baseClaims(input.userId, input.username, input.scopes, input.hubUrl),
|
|
7949
|
+
provider: "oauth-code",
|
|
7950
|
+
redirectUri: input.redirectUri,
|
|
7951
|
+
integrationId: input.integrationId,
|
|
7952
|
+
jti
|
|
7953
|
+
},
|
|
7954
|
+
ttlSec: TTL["oauth-code"]
|
|
7955
|
+
});
|
|
7956
|
+
return { code: token };
|
|
7957
|
+
},
|
|
7958
|
+
async oauthExchangeCode(input) {
|
|
7959
|
+
const claims = await ssoBridge.verifyBridgeToken({ token: input.code });
|
|
7960
|
+
if (!claims || claims.provider !== "oauth-code") return null;
|
|
7961
|
+
if (claims.redirectUri !== input.redirectUri) return null;
|
|
7962
|
+
const jti = claims.jti;
|
|
7963
|
+
if (!jti) return null;
|
|
7964
|
+
const expiryMs = Date.now() + TTL["oauth-code"] * 1e3;
|
|
7965
|
+
if (consumedJtis.has(jti)) return null;
|
|
7966
|
+
consumedJtis.set(jti, expiryMs);
|
|
7967
|
+
setTimeout(() => {
|
|
7968
|
+
consumedJtis.delete(jti);
|
|
7969
|
+
}, TTL["oauth-code"] * 1e3).unref?.();
|
|
7970
|
+
const scopes = claims.scopes ?? [];
|
|
7971
|
+
const session = await sessionManager.create({
|
|
7972
|
+
userId: claims.userId,
|
|
7973
|
+
username: claims.username,
|
|
7974
|
+
integrationId: typeof claims.integrationId === "string" ? claims.integrationId : "<unknown>",
|
|
7975
|
+
scopes
|
|
7976
|
+
});
|
|
7977
|
+
return mintPair(claims.userId, claims.username, scopes, claims.hubUrl ?? "", session.id);
|
|
7978
|
+
},
|
|
7979
|
+
async oauthRefresh(input) {
|
|
7980
|
+
const claims = await ssoBridge.verifyBridgeToken({ token: input.refreshToken });
|
|
7981
|
+
if (!claims || claims.provider !== "oauth-refresh") return null;
|
|
7982
|
+
const sessionId = typeof claims.sessionId === "string" ? claims.sessionId : null;
|
|
7983
|
+
if (!sessionId) return null;
|
|
7984
|
+
const session = await sessionManager.getById(sessionId);
|
|
7985
|
+
if (!session || session.revokedAt != null) return null;
|
|
7986
|
+
await sessionManager.touch(sessionId);
|
|
7987
|
+
const scopes = claims.scopes ?? [];
|
|
7988
|
+
return mintPair(claims.userId, claims.username, scopes, claims.hubUrl ?? "", sessionId);
|
|
7989
|
+
},
|
|
7990
|
+
async oauthVerifyAccessToken(input) {
|
|
7991
|
+
const claims = await ssoBridge.verifyBridgeToken({ token: input.token });
|
|
7992
|
+
if (!claims || claims.provider !== "oauth-access") return null;
|
|
7993
|
+
const sessionId = typeof claims.sessionId === "string" ? claims.sessionId : null;
|
|
7994
|
+
if (!sessionId) return null;
|
|
7995
|
+
const session = await sessionManager.getById(sessionId);
|
|
7996
|
+
if (!session || session.revokedAt != null) return null;
|
|
7997
|
+
return {
|
|
7998
|
+
userId: claims.userId,
|
|
7999
|
+
username: claims.username,
|
|
8000
|
+
scopes: claims.scopes ?? []
|
|
8001
|
+
};
|
|
8002
|
+
}
|
|
8003
|
+
};
|
|
7698
8004
|
}
|
|
7699
8005
|
//#endregion
|
|
7700
8006
|
//#region src/builtins/local-auth/local-auth.addon.ts
|
|
@@ -7711,6 +8017,7 @@ var LocalAuthAddon = class extends _camstack_types.BaseAddon {
|
|
|
7711
8017
|
userManager = null;
|
|
7712
8018
|
apiKeyManager = null;
|
|
7713
8019
|
scopedTokenManager = null;
|
|
8020
|
+
oauthSessionManager = null;
|
|
7714
8021
|
totpManager = null;
|
|
7715
8022
|
constructor() {
|
|
7716
8023
|
super({
|
|
@@ -7744,6 +8051,7 @@ var LocalAuthAddon = class extends _camstack_types.BaseAddon {
|
|
|
7744
8051
|
this.userManager = new UserManager(storageAccess, this.authManager, reader);
|
|
7745
8052
|
this.apiKeyManager = new ApiKeyManager(storageAccess, this.authManager);
|
|
7746
8053
|
this.scopedTokenManager = new ScopedTokenManager(store);
|
|
8054
|
+
this.oauthSessionManager = new OauthSessionManager(store);
|
|
7747
8055
|
this.totpManager = new TotpManager(store);
|
|
7748
8056
|
try {
|
|
7749
8057
|
await this.userManager.ensureAdminExists();
|
|
@@ -7780,6 +8088,19 @@ var LocalAuthAddon = class extends _camstack_types.BaseAddon {
|
|
|
7780
8088
|
}
|
|
7781
8089
|
}
|
|
7782
8090
|
};
|
|
8091
|
+
let cachedOauthGrants = null;
|
|
8092
|
+
const lazyOauthGrants = () => {
|
|
8093
|
+
if (cachedOauthGrants) return cachedOauthGrants;
|
|
8094
|
+
const bridgeApi = this.ctx.api?.ssoBridge;
|
|
8095
|
+
if (!bridgeApi) throw new Error("local-auth: sso-bridge capability not available via ctx.api — hub boot incomplete");
|
|
8096
|
+
const ssoBridgeProvider = {
|
|
8097
|
+
signBridgeToken: (input) => bridgeApi.signBridgeToken.query(input),
|
|
8098
|
+
verifyBridgeToken: (input) => bridgeApi.verifyBridgeToken.query(input)
|
|
8099
|
+
};
|
|
8100
|
+
if (!this.oauthSessionManager) throw new Error("local-auth: oauthSessionManager not initialized — hub boot incomplete");
|
|
8101
|
+
cachedOauthGrants = createOauthGrants(ssoBridgeProvider, this.oauthSessionManager);
|
|
8102
|
+
return cachedOauthGrants;
|
|
8103
|
+
};
|
|
7783
8104
|
const userMgmt = {
|
|
7784
8105
|
listUsers: async () => {
|
|
7785
8106
|
if (!this.userManager) return [];
|
|
@@ -7879,6 +8200,35 @@ var LocalAuthAddon = class extends _camstack_types.BaseAddon {
|
|
|
7879
8200
|
if (!this.scopedTokenManager) return [];
|
|
7880
8201
|
return this.scopedTokenManager.listForUser(input.userId);
|
|
7881
8202
|
},
|
|
8203
|
+
oauthIssueCode: async (input) => {
|
|
8204
|
+
return lazyOauthGrants().oauthIssueCode(input);
|
|
8205
|
+
},
|
|
8206
|
+
oauthExchangeCode: async (input) => {
|
|
8207
|
+
return lazyOauthGrants().oauthExchangeCode(input);
|
|
8208
|
+
},
|
|
8209
|
+
oauthRefresh: async (input) => {
|
|
8210
|
+
return lazyOauthGrants().oauthRefresh(input);
|
|
8211
|
+
},
|
|
8212
|
+
oauthVerifyAccessToken: async (input) => {
|
|
8213
|
+
return lazyOauthGrants().oauthVerifyAccessToken(input);
|
|
8214
|
+
},
|
|
8215
|
+
listOauthSessions: async () => {
|
|
8216
|
+
if (!this.oauthSessionManager) return [];
|
|
8217
|
+
return (await this.oauthSessionManager.list()).map((s) => ({
|
|
8218
|
+
id: s.id,
|
|
8219
|
+
userId: s.userId,
|
|
8220
|
+
username: s.username,
|
|
8221
|
+
integrationId: s.integrationId,
|
|
8222
|
+
scopes: s.scopes,
|
|
8223
|
+
createdAt: s.createdAt,
|
|
8224
|
+
lastUsedAt: s.lastUsedAt,
|
|
8225
|
+
revokedAt: s.revokedAt
|
|
8226
|
+
}));
|
|
8227
|
+
},
|
|
8228
|
+
revokeOauthSession: async (input) => {
|
|
8229
|
+
if (!this.oauthSessionManager) return { success: false };
|
|
8230
|
+
return { success: await this.oauthSessionManager.markRevoked(input.id) };
|
|
8231
|
+
},
|
|
7882
8232
|
setupTotp: async (input) => {
|
|
7883
8233
|
if (!this.totpManager || !this.userManager) throw new Error("TOTP management not available");
|
|
7884
8234
|
const user = await this.userManager.findById(input.userId);
|
|
@@ -7921,6 +8271,7 @@ var LocalAuthAddon = class extends _camstack_types.BaseAddon {
|
|
|
7921
8271
|
this.userManager = null;
|
|
7922
8272
|
this.apiKeyManager = null;
|
|
7923
8273
|
this.scopedTokenManager = null;
|
|
8274
|
+
this.oauthSessionManager = null;
|
|
7924
8275
|
}
|
|
7925
8276
|
};
|
|
7926
8277
|
//#endregion
|