@absolutejs/auth 0.27.0-beta.8 → 0.27.0-beta.9
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/adaptive/config.d.ts +13 -1
- package/dist/adaptive/fingerprint.d.ts +2 -0
- package/dist/adaptive/types.d.ts +13 -1
- package/dist/audit/export.d.ts +2 -0
- package/dist/audit/types.d.ts +1 -0
- package/dist/fga/config.d.ts +8 -0
- package/dist/fga/schema.d.ts +2 -0
- package/dist/fga/types.d.ts +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +193 -18
- package/dist/index.js.map +14 -11
- package/package.json +1 -1
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import type { KnownDeviceStore, LoginHistoryStore, RiskAction, RiskAssessment, RiskContext, RiskSignal } from './types';
|
|
1
|
+
import type { KnownDeviceStore, LoginHistoryStore, RiskAction, RiskAssessment, RiskContext, RiskSignal, RiskThresholds, RiskWeights, WeightedRiskAssessment } from './types';
|
|
2
2
|
export type AdaptiveConfig = {
|
|
3
3
|
historyLimit?: number;
|
|
4
4
|
knownDeviceStore: KnownDeviceStore;
|
|
5
5
|
loginHistoryStore: LoginHistoryStore;
|
|
6
6
|
maxTravelKmh?: number;
|
|
7
|
+
offHours?: {
|
|
8
|
+
end: number;
|
|
9
|
+
start: number;
|
|
10
|
+
};
|
|
7
11
|
rules?: Partial<Record<RiskSignal, RiskAction>>;
|
|
8
12
|
velocityMaxAttempts?: number;
|
|
9
13
|
velocityWindowMs?: number;
|
|
@@ -14,9 +18,17 @@ export declare const createRiskEngine: (config: AdaptiveConfig) => {
|
|
|
14
18
|
recordAttempt: (context: RiskContext & {
|
|
15
19
|
outcome: RiskAction;
|
|
16
20
|
}) => Promise<void>;
|
|
21
|
+
scoreRisk: (context: RiskContext, options?: {
|
|
22
|
+
thresholds?: RiskThresholds;
|
|
23
|
+
weights?: RiskWeights;
|
|
24
|
+
}) => Promise<WeightedRiskAssessment>;
|
|
17
25
|
trustDevice: (userId: string, deviceId: string, label?: string) => Promise<void>;
|
|
18
26
|
};
|
|
19
27
|
export declare const recordLoginAttempt: (config: AdaptiveConfig, context: RiskContext & {
|
|
20
28
|
outcome: RiskAction;
|
|
21
29
|
}) => Promise<void>;
|
|
30
|
+
export declare const scoreRisk: (config: AdaptiveConfig & {
|
|
31
|
+
thresholds?: RiskThresholds;
|
|
32
|
+
weights?: RiskWeights;
|
|
33
|
+
}, context: RiskContext) => Promise<WeightedRiskAssessment>;
|
|
22
34
|
export declare const trustDevice: (config: AdaptiveConfig, userId: string, deviceId: string, label?: string) => Promise<void>;
|
package/dist/adaptive/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type RiskAction = 'allow' | 'deny' | 'step_up';
|
|
2
|
-
export type RiskSignal = 'impossible_travel' | 'new_country' | 'new_device' | 'velocity';
|
|
2
|
+
export type RiskSignal = 'impossible_travel' | 'new_country' | 'new_device' | 'off_hours' | 'proxy' | 'velocity';
|
|
3
3
|
export type GeoPoint = {
|
|
4
4
|
country?: string;
|
|
5
5
|
latitude?: number;
|
|
@@ -9,6 +9,8 @@ export type RiskContext = {
|
|
|
9
9
|
deviceId: string;
|
|
10
10
|
geo?: GeoPoint;
|
|
11
11
|
ipAddress?: string;
|
|
12
|
+
isProxy?: boolean;
|
|
13
|
+
localHour?: number;
|
|
12
14
|
now?: number;
|
|
13
15
|
userId: string;
|
|
14
16
|
};
|
|
@@ -20,6 +22,16 @@ export type RiskAssessment = {
|
|
|
20
22
|
action: RiskAction;
|
|
21
23
|
reasons: RiskReason[];
|
|
22
24
|
};
|
|
25
|
+
export type RiskWeights = Partial<Record<RiskSignal, number>>;
|
|
26
|
+
export type RiskThresholds = {
|
|
27
|
+
deny: number;
|
|
28
|
+
stepUp: number;
|
|
29
|
+
};
|
|
30
|
+
export type WeightedRiskAssessment = {
|
|
31
|
+
action: RiskAction;
|
|
32
|
+
reasons: RiskReason[];
|
|
33
|
+
score: number;
|
|
34
|
+
};
|
|
23
35
|
export type KnownDevice = {
|
|
24
36
|
deviceId: string;
|
|
25
37
|
firstSeenAt: number;
|
package/dist/audit/types.d.ts
CHANGED
package/dist/fga/config.d.ts
CHANGED
|
@@ -15,10 +15,17 @@ export type Subject = {
|
|
|
15
15
|
subjectId: string;
|
|
16
16
|
subjectType: string;
|
|
17
17
|
};
|
|
18
|
+
export type ObjectQuery = {
|
|
19
|
+
relation: string;
|
|
20
|
+
resourceType: string;
|
|
21
|
+
subjectId: string;
|
|
22
|
+
subjectType: string;
|
|
23
|
+
};
|
|
18
24
|
export declare const check: (config: FgaConfig, query: CheckQuery) => Promise<boolean>;
|
|
19
25
|
export declare const createFgaEngine: (config: FgaConfig) => {
|
|
20
26
|
check: (query: CheckQuery) => Promise<boolean>;
|
|
21
27
|
deleteWarrant: (warrant: Warrant) => Promise<void>;
|
|
28
|
+
listObjects: (query: ObjectQuery) => Promise<string[]>;
|
|
22
29
|
listSubjects: (query: {
|
|
23
30
|
relation: string;
|
|
24
31
|
resourceId: string;
|
|
@@ -27,6 +34,7 @@ export declare const createFgaEngine: (config: FgaConfig) => {
|
|
|
27
34
|
writeWarrant: (warrant: Warrant) => Promise<void>;
|
|
28
35
|
};
|
|
29
36
|
export declare const deleteWarrant: (config: FgaConfig, warrant: Warrant) => Promise<void>;
|
|
37
|
+
export declare const listObjects: (config: FgaConfig, query: ObjectQuery) => Promise<string[]>;
|
|
30
38
|
export declare const listSubjects: (config: FgaConfig, query: {
|
|
31
39
|
relation: string;
|
|
32
40
|
resourceId: string;
|
package/dist/fga/types.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export type Warrant = {
|
|
|
9
9
|
export type WarrantStore = {
|
|
10
10
|
deleteWarrant: (warrant: Warrant) => Promise<void>;
|
|
11
11
|
listForResource: (resourceType: string, resourceId: string, relation: string) => Promise<Warrant[]>;
|
|
12
|
+
listResourceIds: (resourceType: string) => Promise<string[]>;
|
|
12
13
|
saveWarrant: (warrant: Warrant) => Promise<void>;
|
|
13
14
|
};
|
|
14
15
|
export type RelationRule = {
|
package/dist/index.d.ts
CHANGED
|
@@ -14712,6 +14712,7 @@ export { createInMemoryLockoutStore } from './lockout/inMemoryLockoutStore';
|
|
|
14712
14712
|
export { createNeonLockoutStore, createPostgresLockoutStore, lockoutsTable } from './lockout/postgresLockoutStore';
|
|
14713
14713
|
export { createRedisLockoutStore } from './lockout/redisLockoutStore';
|
|
14714
14714
|
export type { RedisLike } from './stores/redis';
|
|
14715
|
+
export { exportAuditCsv } from './audit/export';
|
|
14715
14716
|
export { createInMemoryAuditSink } from './audit/inMemoryAuditStore';
|
|
14716
14717
|
export { auditEventsTable, createNeonAuditSink, createPostgresAuditSink } from './audit/postgresAuditStore';
|
|
14717
14718
|
export * from './sso/types';
|
|
@@ -14736,10 +14737,12 @@ export type { DpopResult } from './oidc/dpop';
|
|
|
14736
14737
|
export { createInMemoryAuthorizationCodeStore, createInMemoryOAuthClientStore, createInMemoryOidcRefreshTokenStore } from './oidc/inMemoryStores';
|
|
14737
14738
|
export { createNeonAuthorizationCodeStore, createNeonOAuthClientStore, createNeonOidcRefreshTokenStore, createPostgresAuthorizationCodeStore, createPostgresOAuthClientStore, createPostgresOidcRefreshTokenStore, oauthClientsTable, oauthCodesTable, oauthRefreshTokensTable } from './oidc/postgresStores';
|
|
14738
14739
|
export * from './adaptive/config';
|
|
14740
|
+
export * from './adaptive/fingerprint';
|
|
14739
14741
|
export * from './adaptive/types';
|
|
14740
14742
|
export { createInMemoryKnownDeviceStore, createInMemoryLoginHistoryStore } from './adaptive/inMemoryStores';
|
|
14741
14743
|
export { createNeonKnownDeviceStore, createNeonLoginHistoryStore, createPostgresKnownDeviceStore, createPostgresLoginHistoryStore, knownDevicesTable, loginHistoryTable } from './adaptive/postgresStores';
|
|
14742
14744
|
export * from './fga/config';
|
|
14745
|
+
export * from './fga/schema';
|
|
14743
14746
|
export * from './fga/types';
|
|
14744
14747
|
export { createInMemoryWarrantStore, warrantKey } from './fga/inMemoryStores';
|
|
14745
14748
|
export { createNeonWarrantStore, createPostgresWarrantStore, warrantsTable } from './fga/postgresStores';
|
package/dist/index.js
CHANGED
|
@@ -18769,6 +18769,7 @@ var createTamperEvidentSink = ({
|
|
|
18769
18769
|
};
|
|
18770
18770
|
return {
|
|
18771
18771
|
list: sink.list,
|
|
18772
|
+
prune: sink.prune,
|
|
18772
18773
|
append: async (event) => {
|
|
18773
18774
|
await seed();
|
|
18774
18775
|
const previousHash = lastHash ?? GENESIS;
|
|
@@ -19084,6 +19085,19 @@ var createRedisLockoutStore = (redis, keyPrefix = DEFAULT_PREFIX) => {
|
|
|
19084
19085
|
}
|
|
19085
19086
|
};
|
|
19086
19087
|
};
|
|
19088
|
+
// src/audit/export.ts
|
|
19089
|
+
var CSV_HEADER = "at,type,userId,ip,organizationId,metadata";
|
|
19090
|
+
var escapeCsv = (value) => /[",\n\r]/u.test(value) ? `"${value.replace(/"/gu, '""')}"` : value;
|
|
19091
|
+
var toRow = (event) => [
|
|
19092
|
+
new Date(event.at).toISOString(),
|
|
19093
|
+
event.type,
|
|
19094
|
+
event.userId ?? "",
|
|
19095
|
+
event.ip ?? "",
|
|
19096
|
+
event.organizationId ?? "",
|
|
19097
|
+
event.metadata ? JSON.stringify(event.metadata) : ""
|
|
19098
|
+
].map(escapeCsv).join(",");
|
|
19099
|
+
var exportAuditCsv = (events) => [CSV_HEADER, ...events.map(toRow)].join(`
|
|
19100
|
+
`);
|
|
19087
19101
|
// src/audit/inMemoryAuditStore.ts
|
|
19088
19102
|
var createInMemoryAuditSink = () => {
|
|
19089
19103
|
const events = [];
|
|
@@ -19096,6 +19110,13 @@ var createInMemoryAuditSink = () => {
|
|
|
19096
19110
|
const ordered = [...matched].sort((left, right) => right.at - left.at);
|
|
19097
19111
|
const limited = filter?.limit === undefined ? ordered : ordered.slice(0, filter.limit);
|
|
19098
19112
|
return limited.map((event) => ({ ...event }));
|
|
19113
|
+
},
|
|
19114
|
+
prune: async (before) => {
|
|
19115
|
+
const kept = events.filter((event) => event.at >= before);
|
|
19116
|
+
const removed = events.length - kept.length;
|
|
19117
|
+
events.length = 0;
|
|
19118
|
+
events.push(...kept);
|
|
19119
|
+
return removed;
|
|
19099
19120
|
}
|
|
19100
19121
|
};
|
|
19101
19122
|
};
|
|
@@ -19137,6 +19158,10 @@ var createPostgresAuditSink = (db) => ({
|
|
|
19137
19158
|
list: async (filter) => {
|
|
19138
19159
|
const rows = await db.select().from(auditEventsTable).where(filter?.userId ? eq(auditEventsTable.user_id, filter.userId) : undefined).orderBy(desc(auditEventsTable.at_ms)).limit(filter?.limit ?? DEFAULT_AUDIT_LIMIT);
|
|
19139
19160
|
return rows.map(toEvent);
|
|
19161
|
+
},
|
|
19162
|
+
prune: async (before) => {
|
|
19163
|
+
const deleted = await db.delete(auditEventsTable).where(lt(auditEventsTable.at_ms, before)).returning({ id: auditEventsTable.id });
|
|
19164
|
+
return deleted.length;
|
|
19140
19165
|
}
|
|
19141
19166
|
});
|
|
19142
19167
|
// src/scim/inMemoryScimTokenStore.ts
|
|
@@ -19573,8 +19598,22 @@ var DEFAULT_RULE_ACTIONS = {
|
|
|
19573
19598
|
impossible_travel: "deny",
|
|
19574
19599
|
new_country: "step_up",
|
|
19575
19600
|
new_device: "step_up",
|
|
19601
|
+
off_hours: "allow",
|
|
19602
|
+
proxy: "step_up",
|
|
19576
19603
|
velocity: "deny"
|
|
19577
19604
|
};
|
|
19605
|
+
var DEFAULT_RISK_WEIGHTS = {
|
|
19606
|
+
impossible_travel: 80,
|
|
19607
|
+
new_country: 25,
|
|
19608
|
+
new_device: 20,
|
|
19609
|
+
off_hours: 10,
|
|
19610
|
+
proxy: 30,
|
|
19611
|
+
velocity: 80
|
|
19612
|
+
};
|
|
19613
|
+
var DEFAULT_OFF_HOURS_START = 0;
|
|
19614
|
+
var DEFAULT_OFF_HOURS_END = 6;
|
|
19615
|
+
var DEFAULT_DENY_SCORE = 80;
|
|
19616
|
+
var DEFAULT_STEP_UP_SCORE = 40;
|
|
19578
19617
|
var toRadians = (degrees) => degrees * Math.PI / DEGREES_PER_HALF_TURN;
|
|
19579
19618
|
var haversineKm = (start, end) => {
|
|
19580
19619
|
if (start.latitude === undefined || start.longitude === undefined || end.latitude === undefined || end.longitude === undefined) {
|
|
@@ -19588,32 +19627,44 @@ var haversineKm = (start, end) => {
|
|
|
19588
19627
|
return HALF * EARTH_RADIUS_KM * Math.asin(Math.sqrt(factor));
|
|
19589
19628
|
};
|
|
19590
19629
|
var mostSevere2 = (reasons) => reasons.reduce((worst, reason) => ACTION_SEVERITY2[reason.action] > ACTION_SEVERITY2[worst] ? reason.action : worst, "allow");
|
|
19591
|
-
var
|
|
19630
|
+
var isWithinOffHours = (hour, range) => {
|
|
19631
|
+
const start = range?.start ?? DEFAULT_OFF_HOURS_START;
|
|
19632
|
+
const end = range?.end ?? DEFAULT_OFF_HOURS_END;
|
|
19633
|
+
if (start <= end)
|
|
19634
|
+
return hour >= start && hour < end;
|
|
19635
|
+
return hour >= start || hour < end;
|
|
19636
|
+
};
|
|
19637
|
+
var actionForScore = (score, thresholds) => {
|
|
19638
|
+
const deny = "deny";
|
|
19639
|
+
const stepUp = "step_up";
|
|
19640
|
+
const allow = "allow";
|
|
19641
|
+
if (score >= thresholds.deny)
|
|
19642
|
+
return deny;
|
|
19643
|
+
if (score >= thresholds.stepUp)
|
|
19644
|
+
return stepUp;
|
|
19645
|
+
return allow;
|
|
19646
|
+
};
|
|
19647
|
+
var detectSignals = async (config, context) => {
|
|
19592
19648
|
const {
|
|
19593
19649
|
historyLimit = DEFAULT_HISTORY_LIMIT,
|
|
19594
19650
|
knownDeviceStore,
|
|
19595
19651
|
loginHistoryStore,
|
|
19596
19652
|
maxTravelKmh = DEFAULT_MAX_TRAVEL_KMH,
|
|
19597
|
-
|
|
19653
|
+
offHours,
|
|
19598
19654
|
velocityMaxAttempts = DEFAULT_VELOCITY_MAX_ATTEMPTS,
|
|
19599
19655
|
velocityWindowMs = DEFAULT_VELOCITY_WINDOW_MS
|
|
19600
19656
|
} = config;
|
|
19601
19657
|
const now = context.now ?? Date.now();
|
|
19602
|
-
const
|
|
19603
|
-
...DEFAULT_RULE_ACTIONS,
|
|
19604
|
-
...rules
|
|
19605
|
-
};
|
|
19606
|
-
const reasons = [];
|
|
19658
|
+
const fired = [];
|
|
19607
19659
|
const [device, history] = await Promise.all([
|
|
19608
19660
|
knownDeviceStore.findDevice(context.userId, context.deviceId),
|
|
19609
19661
|
loginHistoryStore.listRecent(context.userId, historyLimit)
|
|
19610
19662
|
]);
|
|
19611
|
-
if (device === undefined || !device.trusted)
|
|
19612
|
-
|
|
19613
|
-
}
|
|
19663
|
+
if (device === undefined || !device.trusted)
|
|
19664
|
+
fired.push("new_device");
|
|
19614
19665
|
const country = context.geo?.country;
|
|
19615
19666
|
if (country !== undefined && history.length > 0 && !history.some((attempt) => attempt.country === country)) {
|
|
19616
|
-
|
|
19667
|
+
fired.push("new_country");
|
|
19617
19668
|
}
|
|
19618
19669
|
const [previous] = history;
|
|
19619
19670
|
const traveledKm = previous !== undefined && context.geo !== undefined ? haversineKm({
|
|
@@ -19622,20 +19673,34 @@ var assessRisk = async (config, context) => {
|
|
|
19622
19673
|
}, context.geo) : undefined;
|
|
19623
19674
|
const hours = previous === undefined ? 0 : (now - previous.timestamp) / MILLISECONDS_IN_AN_HOUR;
|
|
19624
19675
|
if (traveledKm !== undefined && hours > 0 && traveledKm / hours > maxTravelKmh) {
|
|
19625
|
-
|
|
19626
|
-
action: actions.impossible_travel,
|
|
19627
|
-
signal: "impossible_travel"
|
|
19628
|
-
});
|
|
19676
|
+
fired.push("impossible_travel");
|
|
19629
19677
|
}
|
|
19630
19678
|
const recentCount = history.filter((attempt) => now - attempt.timestamp <= velocityWindowMs).length;
|
|
19631
|
-
if (recentCount >= velocityMaxAttempts)
|
|
19632
|
-
|
|
19679
|
+
if (recentCount >= velocityMaxAttempts)
|
|
19680
|
+
fired.push("velocity");
|
|
19681
|
+
if (context.isProxy === true)
|
|
19682
|
+
fired.push("proxy");
|
|
19683
|
+
if (context.localHour !== undefined && isWithinOffHours(context.localHour, offHours)) {
|
|
19684
|
+
fired.push("off_hours");
|
|
19633
19685
|
}
|
|
19686
|
+
return fired;
|
|
19687
|
+
};
|
|
19688
|
+
var assessRisk = async (config, context) => {
|
|
19689
|
+
const actions = {
|
|
19690
|
+
...DEFAULT_RULE_ACTIONS,
|
|
19691
|
+
...config.rules
|
|
19692
|
+
};
|
|
19693
|
+
const fired = await detectSignals(config, context);
|
|
19694
|
+
const reasons = fired.map((signal) => ({
|
|
19695
|
+
action: actions[signal],
|
|
19696
|
+
signal
|
|
19697
|
+
}));
|
|
19634
19698
|
return { action: mostSevere2(reasons), reasons };
|
|
19635
19699
|
};
|
|
19636
19700
|
var createRiskEngine = (config) => ({
|
|
19637
19701
|
assessRisk: (context) => assessRisk(config, context),
|
|
19638
19702
|
recordAttempt: (context) => recordLoginAttempt(config, context),
|
|
19703
|
+
scoreRisk: (context, options) => scoreRisk({ ...config, ...options }, context),
|
|
19639
19704
|
trustDevice: (userId, deviceId, label) => trustDevice(config, userId, deviceId, label)
|
|
19640
19705
|
});
|
|
19641
19706
|
var recordLoginAttempt = async (config, context) => {
|
|
@@ -19661,6 +19726,22 @@ var recordLoginAttempt = async (config, context) => {
|
|
|
19661
19726
|
userId: context.userId
|
|
19662
19727
|
});
|
|
19663
19728
|
};
|
|
19729
|
+
var scoreRisk = async (config, context) => {
|
|
19730
|
+
const weights = {
|
|
19731
|
+
...DEFAULT_RISK_WEIGHTS,
|
|
19732
|
+
...config.weights
|
|
19733
|
+
};
|
|
19734
|
+
const defaultThresholds = {
|
|
19735
|
+
deny: DEFAULT_DENY_SCORE,
|
|
19736
|
+
stepUp: DEFAULT_STEP_UP_SCORE
|
|
19737
|
+
};
|
|
19738
|
+
const thresholds = config.thresholds ?? defaultThresholds;
|
|
19739
|
+
const fired = await detectSignals(config, context);
|
|
19740
|
+
const score = fired.reduce((sum, signal) => sum + weights[signal], 0);
|
|
19741
|
+
const action = actionForScore(score, thresholds);
|
|
19742
|
+
const reasons = fired.map((signal) => ({ action, signal }));
|
|
19743
|
+
return { action, reasons, score };
|
|
19744
|
+
};
|
|
19664
19745
|
var trustDevice = async (config, userId, deviceId, label) => {
|
|
19665
19746
|
const now = Date.now();
|
|
19666
19747
|
const existing = await config.knownDeviceStore.findDevice(userId, deviceId);
|
|
@@ -19673,6 +19754,9 @@ var trustDevice = async (config, userId, deviceId, label) => {
|
|
|
19673
19754
|
userId
|
|
19674
19755
|
});
|
|
19675
19756
|
};
|
|
19757
|
+
// src/adaptive/fingerprint.ts
|
|
19758
|
+
var canonical = (signals) => JSON.stringify(signals, (_key, value) => value === null || typeof value !== "object" || Array.isArray(value) ? value : Object.fromEntries(Object.entries(value).sort((left, right) => left[0].localeCompare(right[0]))));
|
|
19759
|
+
var fingerprintDevice = (signals) => hashToken(canonical(signals));
|
|
19676
19760
|
// src/adaptive/inMemoryStores.ts
|
|
19677
19761
|
var deviceKey = (userId, deviceId) => `${userId}:${deviceId}`;
|
|
19678
19762
|
var createInMemoryKnownDeviceStore = () => {
|
|
@@ -19872,16 +19956,95 @@ var expandRule = async (config, resourceType, resourceId, relation, rule, depth,
|
|
|
19872
19956
|
var createFgaEngine = (config) => ({
|
|
19873
19957
|
check: (query) => check(config, query),
|
|
19874
19958
|
deleteWarrant: (warrant) => deleteWarrant(config, warrant),
|
|
19959
|
+
listObjects: (query) => listObjects(config, query),
|
|
19875
19960
|
listSubjects: (query) => listSubjects(config, query),
|
|
19876
19961
|
writeWarrant: (warrant) => writeWarrant(config, warrant)
|
|
19877
19962
|
});
|
|
19878
19963
|
var deleteWarrant = (config, warrant) => config.warrantStore.deleteWarrant(warrant);
|
|
19964
|
+
var listObjects = async (config, query) => {
|
|
19965
|
+
const candidates = await config.warrantStore.listResourceIds(query.resourceType);
|
|
19966
|
+
const allowed = await Promise.all(candidates.map((resourceId) => check(config, {
|
|
19967
|
+
relation: query.relation,
|
|
19968
|
+
resourceId,
|
|
19969
|
+
resourceType: query.resourceType,
|
|
19970
|
+
subjectId: query.subjectId,
|
|
19971
|
+
subjectType: query.subjectType
|
|
19972
|
+
})));
|
|
19973
|
+
return candidates.filter((_resourceId, index) => allowed[index] === true);
|
|
19974
|
+
};
|
|
19879
19975
|
var listSubjects = async (config, query) => {
|
|
19880
19976
|
const found = new Map;
|
|
19881
19977
|
await expand(config, query.resourceType, query.resourceId, query.relation, config.maxDepth ?? DEFAULT_MAX_DEPTH, found, new Set);
|
|
19882
19978
|
return [...found.values()];
|
|
19883
19979
|
};
|
|
19884
19980
|
var writeWarrant = (config, warrant) => config.warrantStore.saveWarrant(warrant);
|
|
19981
|
+
// src/fga/schema.ts
|
|
19982
|
+
var TYPE_PATTERN = /^type\s+(\w+)$/u;
|
|
19983
|
+
var DEFINE_PATTERN = /^define\s+(\w+)\s*:\s*(.+)$/u;
|
|
19984
|
+
var FROM_PATTERN = /^(\w+)\s+from\s+(\w+)$/u;
|
|
19985
|
+
var OR_SEPARATOR = /\s+or\s+/u;
|
|
19986
|
+
var parseTerm = (term) => {
|
|
19987
|
+
const trimmed = term.trim();
|
|
19988
|
+
if (trimmed.startsWith("[")) {
|
|
19989
|
+
const rule2 = { kind: "self" };
|
|
19990
|
+
return rule2;
|
|
19991
|
+
}
|
|
19992
|
+
const fromMatch = FROM_PATTERN.exec(trimmed);
|
|
19993
|
+
if (fromMatch) {
|
|
19994
|
+
const [, relation, viaRelation] = fromMatch;
|
|
19995
|
+
const rule2 = {
|
|
19996
|
+
kind: "tupleToUserset",
|
|
19997
|
+
relation: relation ?? "",
|
|
19998
|
+
viaRelation: viaRelation ?? ""
|
|
19999
|
+
};
|
|
20000
|
+
return rule2;
|
|
20001
|
+
}
|
|
20002
|
+
const rule = { kind: "computedUserset", relation: trimmed };
|
|
20003
|
+
return rule;
|
|
20004
|
+
};
|
|
20005
|
+
var parseExpression = (expression) => {
|
|
20006
|
+
const terms = expression.split(OR_SEPARATOR).map(parseTerm);
|
|
20007
|
+
const [first] = terms;
|
|
20008
|
+
if (terms.length === 1 && first)
|
|
20009
|
+
return first;
|
|
20010
|
+
const rule = { kind: "union", rules: terms };
|
|
20011
|
+
return rule;
|
|
20012
|
+
};
|
|
20013
|
+
var applyType = (schema, line2) => {
|
|
20014
|
+
const match = TYPE_PATTERN.exec(line2);
|
|
20015
|
+
if (!match)
|
|
20016
|
+
return;
|
|
20017
|
+
const [, name] = match;
|
|
20018
|
+
if (name)
|
|
20019
|
+
schema[name] = {};
|
|
20020
|
+
return name;
|
|
20021
|
+
};
|
|
20022
|
+
var applyDefine = (target, line2) => {
|
|
20023
|
+
if (!target)
|
|
20024
|
+
return;
|
|
20025
|
+
const match = DEFINE_PATTERN.exec(line2);
|
|
20026
|
+
if (!match)
|
|
20027
|
+
return;
|
|
20028
|
+
const [, relation, expression] = match;
|
|
20029
|
+
if (relation && expression)
|
|
20030
|
+
target[relation] = parseExpression(expression);
|
|
20031
|
+
};
|
|
20032
|
+
var parseSchema = (dsl) => {
|
|
20033
|
+
const schema = {};
|
|
20034
|
+
let currentType;
|
|
20035
|
+
for (const rawLine of dsl.split(`
|
|
20036
|
+
`)) {
|
|
20037
|
+
const line2 = rawLine.trim();
|
|
20038
|
+
if (line2 === "" || line2.startsWith("#") || line2 === "relations")
|
|
20039
|
+
continue;
|
|
20040
|
+
const typeName = applyType(schema, line2);
|
|
20041
|
+
currentType = typeName ?? currentType;
|
|
20042
|
+
if (typeName !== undefined)
|
|
20043
|
+
continue;
|
|
20044
|
+
applyDefine(currentType ? schema[currentType] : undefined, line2);
|
|
20045
|
+
}
|
|
20046
|
+
return schema;
|
|
20047
|
+
};
|
|
19885
20048
|
// src/fga/inMemoryStores.ts
|
|
19886
20049
|
var createInMemoryWarrantStore = () => {
|
|
19887
20050
|
const warrants = new Map;
|
|
@@ -19890,6 +20053,9 @@ var createInMemoryWarrantStore = () => {
|
|
|
19890
20053
|
warrants.delete(warrantKey(warrant));
|
|
19891
20054
|
},
|
|
19892
20055
|
listForResource: async (resourceType, resourceId, relation) => [...warrants.values()].filter((warrant) => warrant.resourceType === resourceType && warrant.resourceId === resourceId && warrant.relation === relation),
|
|
20056
|
+
listResourceIds: async (resourceType) => [
|
|
20057
|
+
...new Set([...warrants.values()].filter((warrant) => warrant.resourceType === resourceType).map((warrant) => warrant.resourceId))
|
|
20058
|
+
],
|
|
19893
20059
|
saveWarrant: async (warrant) => {
|
|
19894
20060
|
warrants.set(warrantKey(warrant), { ...warrant });
|
|
19895
20061
|
}
|
|
@@ -19924,6 +20090,10 @@ var createPostgresWarrantStore = (db) => ({
|
|
|
19924
20090
|
const rows = await db.select().from(warrantsTable).where(and(eq(warrantsTable.resource_type, resourceType), eq(warrantsTable.resource_id, resourceId), eq(warrantsTable.relation, relation)));
|
|
19925
20091
|
return rows.map(toWarrant);
|
|
19926
20092
|
},
|
|
20093
|
+
listResourceIds: async (resourceType) => {
|
|
20094
|
+
const rows = await db.selectDistinct({ resourceId: warrantsTable.resource_id }).from(warrantsTable).where(eq(warrantsTable.resource_type, resourceType));
|
|
20095
|
+
return rows.map((row) => row.resourceId);
|
|
20096
|
+
},
|
|
19927
20097
|
saveWarrant: async (warrant) => {
|
|
19928
20098
|
await db.insert(warrantsTable).values({
|
|
19929
20099
|
id: warrantKey(warrant),
|
|
@@ -20751,6 +20921,7 @@ export {
|
|
|
20751
20921
|
sessionStore,
|
|
20752
20922
|
sessionRoutes,
|
|
20753
20923
|
sessionCleanup,
|
|
20924
|
+
scoreRisk,
|
|
20754
20925
|
scopeRequiredProviderOptions,
|
|
20755
20926
|
scimTokensTable,
|
|
20756
20927
|
scimRoutes,
|
|
@@ -20781,6 +20952,7 @@ export {
|
|
|
20781
20952
|
pkceProviderOptions,
|
|
20782
20953
|
passwordlessTokensTable,
|
|
20783
20954
|
passwordlessRoutes,
|
|
20955
|
+
parseSchema,
|
|
20784
20956
|
organizationsTable,
|
|
20785
20957
|
organizationRoutes,
|
|
20786
20958
|
organizationMembershipsTable,
|
|
@@ -20802,6 +20974,7 @@ export {
|
|
|
20802
20974
|
listUserOrganizations,
|
|
20803
20975
|
listSubjects,
|
|
20804
20976
|
listRingSessions,
|
|
20977
|
+
listObjects,
|
|
20805
20978
|
knownDevicesTable,
|
|
20806
20979
|
jwkThumbprint,
|
|
20807
20980
|
issueTokenSet,
|
|
@@ -20835,7 +21008,9 @@ export {
|
|
|
20835
21008
|
generateSecureToken,
|
|
20836
21009
|
generateEncryptionKey,
|
|
20837
21010
|
generateBackupCodes,
|
|
21011
|
+
fingerprintDevice,
|
|
20838
21012
|
extractPropFromIdentity,
|
|
21013
|
+
exportAuditCsv,
|
|
20839
21014
|
exchangeToken,
|
|
20840
21015
|
exchangeClientCredentials,
|
|
20841
21016
|
evaluatePassword,
|
|
@@ -20999,5 +21174,5 @@ export {
|
|
|
20999
21174
|
AuthIdentityConflictError
|
|
21000
21175
|
};
|
|
21001
21176
|
|
|
21002
|
-
//# debugId=
|
|
21177
|
+
//# debugId=22C6F88FE2A9D7F764756E2164756E21
|
|
21003
21178
|
//# sourceMappingURL=index.js.map
|