@owlmeans/server-auth-identity 0.1.18-rc.10 → 0.1.18-rc.12
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 +5 -4
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/server-auth-identity/SKILL.md +7 -7
- package/build/helper.d.ts.map +1 -1
- package/build/resolver.d.ts.map +1 -1
- package/build/resolver.js +19 -24
- package/build/resolver.js.map +1 -1
- package/build/resource.d.ts.map +1 -1
- package/build/resource.js +4 -4
- package/build/resource.js.map +1 -1
- package/build/service.d.ts.map +1 -1
- package/build/service.js +9 -13
- package/build/service.js.map +1 -1
- package/package.json +9 -9
- package/src/resolver.ts +19 -25
- package/src/resource.ts +4 -4
- package/src/service.ts +14 -16
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ Mongo-backed local identity resources and provider account linking for OwlMeans
|
|
|
7
7
|
- Registers three Mongo resources: local accounts, local profiles, and provider credentials.
|
|
8
8
|
- Provides `IdentityLinkingService` to map external provider profile details into an OwlMeans `AuthPayload`.
|
|
9
9
|
- Keeps external provider identity separate from local product identity and authorization scopes.
|
|
10
|
-
- Designed to work with `@owlmeans/server-auth`, `@owlmeans/server-oidc-rp`, and product-specific
|
|
10
|
+
- Designed to work with `@owlmeans/server-auth`, `@owlmeans/server-oidc-rp`, and product-specific entrypoint gates.
|
|
11
11
|
|
|
12
12
|
## Installation
|
|
13
13
|
|
|
@@ -43,9 +43,10 @@ import { AUTH_IDENTITY_PROFILE } from '@owlmeans/server-auth-identity'
|
|
|
43
43
|
import type { IdentityProfileResource } from '@owlmeans/server-auth-identity'
|
|
44
44
|
|
|
45
45
|
const profiles = context.resource<IdentityProfileResource>(AUTH_IDENTITY_PROFILE)
|
|
46
|
-
const profile = await profiles.load(profileId
|
|
46
|
+
const profile = await profiles.load({ profileId })
|
|
47
|
+
const scoped = await profiles.load({ entityId, profileId })
|
|
47
48
|
|
|
48
|
-
const { items } = await profiles.list({ entityId
|
|
49
|
+
const { items, total } = await profiles.list({ entityId })
|
|
49
50
|
```
|
|
50
51
|
|
|
51
52
|
## API
|
|
@@ -83,7 +84,7 @@ const { items } = await profiles.list({ entityId, profileId } as any)
|
|
|
83
84
|
- Google/OIDC login is only the provider bootstrap path; durable authorization data lives in `IdentityProfile`.
|
|
84
85
|
- Backend contexts should register `appendAuthService(context)`, then `appendAuthIdentityResources(context)`, then product gate services.
|
|
85
86
|
- Product gates should read `AUTH_IDENTITY_PROFILE`, verify `entityId`, reject expired or blocked profiles, and compare gate params against profile scopes.
|
|
86
|
-
- `Resource.
|
|
87
|
+
- `Resource.take()` is destructive and deletes the record it returns. Never use `take()` for gate or handler reads; use `load(where)` or `list(where)`.
|
|
87
88
|
|
|
88
89
|
## Related Packages
|
|
89
90
|
|
package/agent-meta/manifest.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"package": "@owlmeans/server-auth-identity",
|
|
4
|
-
"version": "0.1.18-rc.
|
|
5
|
-
"generatedAt": "2026-09-
|
|
4
|
+
"version": "0.1.18-rc.12",
|
|
5
|
+
"generatedAt": "2026-09-01T17:39:40.759Z",
|
|
6
6
|
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -8,7 +8,7 @@ user-invocable: false
|
|
|
8
8
|
# @owlmeans/server-auth-identity
|
|
9
9
|
|
|
10
10
|
**Layer:** Server
|
|
11
|
-
**Install:** `"@owlmeans/server-auth-identity": "^0.1.18-rc.
|
|
11
|
+
**Install:** `"@owlmeans/server-auth-identity": "^0.1.18-rc.12"` in `dependencies`
|
|
12
12
|
|
|
13
13
|
## Key Exports
|
|
14
14
|
|
|
@@ -54,12 +54,12 @@ import type { IdentityProfileResource } from '@owlmeans/server-auth-identity'
|
|
|
54
54
|
|
|
55
55
|
const profileRes = ctx.resource<IdentityProfileResource>(AUTH_IDENTITY_PROFILE)
|
|
56
56
|
|
|
57
|
-
//
|
|
58
|
-
const profile = await profileRes.load(profileId
|
|
57
|
+
// One record by any field, or by several at once — read-only, and typed by the resource:
|
|
58
|
+
const profile = await profileRes.load({ profileId })
|
|
59
|
+
const scoped = await profileRes.load({ entityId, profileId })
|
|
59
60
|
|
|
60
|
-
//
|
|
61
|
-
const { items } = await profileRes.list({ entityId,
|
|
62
|
-
const profile = items[0] ?? null
|
|
61
|
+
// Every match, newest first:
|
|
62
|
+
const { items, total } = await profileRes.list({ entityId }, { sort: [{ field: 'createdAt', order: 'desc' }] })
|
|
63
63
|
```
|
|
64
64
|
|
|
65
65
|
### Link an external provider to a local profile
|
|
@@ -120,7 +120,7 @@ by the reference conversion's design.
|
|
|
120
120
|
|
|
121
121
|
## Important Gotchas
|
|
122
122
|
|
|
123
|
-
- **`Resource.
|
|
123
|
+
- **`Resource.take()` is destructive** — it deletes the record it returns. For read-only identity lookups in gates or handlers use `load(where)`, which answers a multi-field query in one call (`load({ type, userId, credential })`), or `list(where, opts)` when you need every match. Never use `take()` in authorization checks.
|
|
124
124
|
- **`IdentityLinkingService` is compatible with `AccountLinkingService`** from `@owlmeans/server-oidc-rp` but defined independently to avoid circular dependency. Both return `AuthPayload`.
|
|
125
125
|
- First-login profiles are created with `ALL_SCOPES` and `AuthRole.User` — the gate layer is initially permissive per entity. Restrict scopes as needed for fine-grained authorization.
|
|
126
126
|
- Account `credential` slug generation retries up to 5 times on duplicate key collision — this is the designed behavior for the Base58 slug space.
|
package/build/helper.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAKrD,eAAO,MAAM,2BAA2B,
|
|
1
|
+
{"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAKrD,eAAO,MAAM,2BAA2B,GACtC,SAAS,YAAY,CAAC,GAAG,CAAC,EAC1B,UAAU,MAAM,KACf,IAUF,CAAA"}
|
package/build/resolver.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../src/resolver.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../src/resolver.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAAgB,MAAM,uBAAuB,CAAA;AA6BhF,eAAO,MAAM,yBAAyB,GACpC,QAAO,MAAwB,KAC9B,qBAkIF,CAAA"}
|
package/build/resolver.js
CHANGED
|
@@ -11,8 +11,6 @@ import { AUTH_IDENTITY_ORG_ENTITY, MAX_ENTITY_SLUG_ATTEMPTS } from './consts.js'
|
|
|
11
11
|
* resolving through `formerSlugs` rather than failing.
|
|
12
12
|
*/
|
|
13
13
|
const CACHE_TTL = 30_000;
|
|
14
|
-
/** What a stored record id looks like. Anything else can only be a slug or a frozen key. */
|
|
15
|
-
const RECORD_ID = /^[0-9a-f]{24}$/i;
|
|
16
14
|
/** A stored record as the contract exposes it. Persisted records always carry an id. */
|
|
17
15
|
const toRef = (entity) => entity == null ? null : {
|
|
18
16
|
id: entity.id, slug: entity.slug, formerSlugs: entity.formerSlugs, iamKey: entity.iamKey,
|
|
@@ -51,28 +49,26 @@ export const makeEntityResolverService = (alias = ENTITY_RESOLVER) => {
|
|
|
51
49
|
}
|
|
52
50
|
const res = resource();
|
|
53
51
|
// Id first: an id is authoritative, so a slug that happens to look like some other entity's
|
|
54
|
-
// id can never shadow it.
|
|
55
|
-
// frozen key external systems still quote.
|
|
56
|
-
|
|
57
|
-
// The shape test is not an optimisation. `load` reads its argument as a record id, and the
|
|
58
|
-
// store turns that into an ObjectId unconditionally — so handing it a slug throws a driver
|
|
59
|
-
// error out of what is meant to be a lookup that simply misses.
|
|
60
|
-
const byId = RECORD_ID.test(value) ? await res.load(value) : null;
|
|
52
|
+
// id can never shadow it. A value that is not a record id simply misses. Then the current
|
|
53
|
+
// slug, then the names it has retired, then the frozen key external systems still quote.
|
|
54
|
+
const byId = await res.load(value);
|
|
61
55
|
if (byId != null)
|
|
62
56
|
return remember(byId, value);
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
57
|
+
const candidates = [
|
|
58
|
+
{ slug: value },
|
|
59
|
+
{ formerSlugs: { $contains: [value] } },
|
|
60
|
+
{ iamKey: value },
|
|
61
|
+
];
|
|
62
|
+
for (const where of candidates) {
|
|
63
|
+
const found = await res.load(where);
|
|
64
|
+
if (found != null)
|
|
65
|
+
return remember(found, value);
|
|
67
66
|
}
|
|
68
67
|
return remember(null, value);
|
|
69
68
|
};
|
|
70
69
|
const service = appendContextual(alias, {
|
|
71
70
|
resolve: async (value) => toRef(await load(value)),
|
|
72
|
-
byId: async (id) =>
|
|
73
|
-
const entity = RECORD_ID.test(id) ? await resource().load(id) : null;
|
|
74
|
-
return toRef(remember(entity, id));
|
|
75
|
-
},
|
|
71
|
+
byId: async (id) => toRef(remember(await resource().load(id), id)),
|
|
76
72
|
mintSlug: async () => {
|
|
77
73
|
const res = resource();
|
|
78
74
|
// A word slug is picked from 2^22 pairs, so a collision is rare — but "rare" is not "never"
|
|
@@ -82,11 +78,10 @@ export const makeEntityResolverService = (alias = ENTITY_RESOLVER) => {
|
|
|
82
78
|
const base = generateWordSlug();
|
|
83
79
|
for (let suffix = 1; suffix <= 3; ++suffix) {
|
|
84
80
|
const candidate = nextSlugCandidate(base, suffix);
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
pager: { size: 1 },
|
|
81
|
+
const taken = await res.load({
|
|
82
|
+
$or: [{ slug: candidate }, { formerSlugs: { $contains: [candidate] } }],
|
|
88
83
|
});
|
|
89
|
-
if (
|
|
84
|
+
if (taken == null)
|
|
90
85
|
return candidate;
|
|
91
86
|
}
|
|
92
87
|
}
|
|
@@ -103,10 +98,10 @@ export const makeEntityResolverService = (alias = ENTITY_RESOLVER) => {
|
|
|
103
98
|
}
|
|
104
99
|
// A slug another entity has ever answered to cannot be taken: tokens and third-party records
|
|
105
100
|
// quoting it would start resolving to the wrong organization.
|
|
106
|
-
const
|
|
107
|
-
|
|
101
|
+
const taken = await res.load({
|
|
102
|
+
$or: [{ slug }, { formerSlugs: { $contains: [slug] } }],
|
|
108
103
|
});
|
|
109
|
-
if (taken
|
|
104
|
+
if (taken != null && taken.id !== id) {
|
|
110
105
|
throw new SyntaxError(`entity:slug-taken:${slug}`);
|
|
111
106
|
}
|
|
112
107
|
forget(entity);
|
package/build/resolver.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolver.js","sourceRoot":"","sources":["../src/resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"resolver.js","sourceRoot":"","sources":["../src/resolver.ts"],"names":[],"mappings":"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"}
|
package/build/resource.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../src/resource.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAmB,uBAAuB,EAAmB,uBAAuB,EAAuB,2BAA2B,EAAa,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAOpM;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,
|
|
1
|
+
{"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../src/resource.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAmB,uBAAuB,EAAmB,uBAAuB,EAAuB,2BAA2B,EAAa,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAOpM;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,GAAI,UAAU,MAAM,KAAG,iBAQxD,CAAA;AAED,eAAO,MAAM,2BAA2B,GAAI,UAAU,MAAM,KAAG,uBAQ9D,CAAA;AAED,eAAO,MAAM,2BAA2B,GAAI,UAAU,MAAM,KAAG,uBAe9D,CAAA;AAED,eAAO,MAAM,+BAA+B,GAAI,UAAU,MAAM,KAAG,2BAOlE,CAAA"}
|
package/build/resource.js
CHANGED
|
@@ -10,21 +10,21 @@ import { AUTH_IDENTITY_ACCOUNT, AUTH_IDENTITY_PROFILE, AUTH_IDENTITY_CREDENTIALS
|
|
|
10
10
|
* slug must stay findable, and uniqueness against it is enforced when a rename is applied.
|
|
11
11
|
*/
|
|
12
12
|
export const makeOrgEntityResource = (dbAlias) => {
|
|
13
|
-
const resource = makeMongoResource(AUTH_IDENTITY_ORG_ENTITY, dbAlias, undefined,
|
|
13
|
+
const resource = makeMongoResource(AUTH_IDENTITY_ORG_ENTITY, dbAlias, undefined, AUTH_IDENTITY_ORG_ENTITY_COLLECTION);
|
|
14
14
|
resource.index('slug', { slug: 1 }, { unique: true });
|
|
15
15
|
resource.index('iamKey', { iamKey: 1 }, { unique: true });
|
|
16
16
|
resource.index('formerSlugs', { formerSlugs: 1 });
|
|
17
17
|
return resource;
|
|
18
18
|
};
|
|
19
19
|
export const makeIdentityAccountResource = (dbAlias) => {
|
|
20
|
-
const resource = makeMongoResource(AUTH_IDENTITY_ACCOUNT, dbAlias, undefined,
|
|
20
|
+
const resource = makeMongoResource(AUTH_IDENTITY_ACCOUNT, dbAlias, undefined, AUTH_IDENTITY_ACCOUNT_COLLECTION);
|
|
21
21
|
resource.index('credential', { credential: 1 }, { unique: true });
|
|
22
22
|
resource.index('entityId', { entityId: 1 });
|
|
23
23
|
resource.index('secret', { secret: 1 }, { unique: true, sparse: true });
|
|
24
24
|
return resource;
|
|
25
25
|
};
|
|
26
26
|
export const makeIdentityProfileResource = (dbAlias) => {
|
|
27
|
-
const resource = makeMongoResource(AUTH_IDENTITY_PROFILE, dbAlias, undefined,
|
|
27
|
+
const resource = makeMongoResource(AUTH_IDENTITY_PROFILE, dbAlias, undefined, AUTH_IDENTITY_PROFILE_COLLECTION);
|
|
28
28
|
/**
|
|
29
29
|
* The account's mongo id — the ONLY ObjectId reference in the identity trio.
|
|
30
30
|
* `profileId` is a composite key (`"{type}:{accountId}"`), `entityId` is the Base58
|
|
@@ -38,7 +38,7 @@ export const makeIdentityProfileResource = (dbAlias) => {
|
|
|
38
38
|
return resource;
|
|
39
39
|
};
|
|
40
40
|
export const makeIdentityCredentialsResource = (dbAlias) => {
|
|
41
|
-
const resource = makeMongoResource(AUTH_IDENTITY_CREDENTIALS, dbAlias, undefined,
|
|
41
|
+
const resource = makeMongoResource(AUTH_IDENTITY_CREDENTIALS, dbAlias, undefined, AUTH_IDENTITY_CREDENTIALS_COLLECTION);
|
|
42
42
|
resource.index('provider', { type: 1, userId: 1, credential: 1 }, { unique: true });
|
|
43
43
|
resource.index('profileId', { profileId: 1 });
|
|
44
44
|
return resource;
|
package/build/resource.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resource.js","sourceRoot":"","sources":["../src/resource.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAE5D,OAAO,EACL,qBAAqB,EAAE,qBAAqB,EAAE,yBAAyB,EAAE,wBAAwB,EACjG,gCAAgC,EAAE,gCAAgC,EAAE,oCAAoC,EACxG,mCAAmC,EACpC,MAAM,aAAa,CAAA;AAEpB;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,OAAgB,EAAqB,EAAE;IAC3E,MAAM,QAAQ,GAAG,iBAAiB,CAChC,wBAAwB,EAAE,OAAO,EAAE,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"resource.js","sourceRoot":"","sources":["../src/resource.ts"],"names":[],"mappings":"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"}
|
package/build/service.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAA8F,sBAAsB,EAAE,MAAM,YAAY,CAAA;AAmBpJ,eAAO,MAAM,0BAA0B,QAAO,sBAqM7C,CAAA"}
|
package/build/service.js
CHANGED
|
@@ -27,18 +27,15 @@ export const makeIdentityLinkingService = () => {
|
|
|
27
27
|
getLinkedProfile: async (details) => {
|
|
28
28
|
const ctx = service.ctx;
|
|
29
29
|
const credsResource = ctx.resource(AUTH_IDENTITY_CREDENTIALS);
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
credential: loginService(details),
|
|
35
|
-
}
|
|
30
|
+
const cred = await credsResource.load({
|
|
31
|
+
type: details.type,
|
|
32
|
+
userId: externalKey(details),
|
|
33
|
+
credential: loginService(details),
|
|
36
34
|
});
|
|
37
|
-
const cred = creds[0] ?? null;
|
|
38
35
|
if (cred == null)
|
|
39
36
|
return null;
|
|
40
37
|
const profileResource = ctx.resource(AUTH_IDENTITY_PROFILE);
|
|
41
|
-
const profile = await profileResource.load(cred.profileId
|
|
38
|
+
const profile = await profileResource.load({ profileId: cred.profileId });
|
|
42
39
|
if (profile == null)
|
|
43
40
|
return null;
|
|
44
41
|
return {
|
|
@@ -107,7 +104,7 @@ export const makeIdentityLinkingService = () => {
|
|
|
107
104
|
}
|
|
108
105
|
catch (err) {
|
|
109
106
|
if (err?.code === 11000 || err?.message?.includes('duplicate')) {
|
|
110
|
-
profile = await profileResource.get(profileId
|
|
107
|
+
profile = await profileResource.get({ profileId });
|
|
111
108
|
}
|
|
112
109
|
else {
|
|
113
110
|
throw err;
|
|
@@ -150,7 +147,7 @@ export const makeIdentityLinkingService = () => {
|
|
|
150
147
|
getOwnerProfiles: async (entityId) => {
|
|
151
148
|
const ctx = service.ctx;
|
|
152
149
|
const profileResource = ctx.resource(AUTH_IDENTITY_PROFILE);
|
|
153
|
-
const { items: profiles } = await profileResource.list({
|
|
150
|
+
const { items: profiles } = await profileResource.list({ entityId });
|
|
154
151
|
return await Promise.all(profiles.map(async (p) => ({
|
|
155
152
|
id: p.profileId,
|
|
156
153
|
name: p.name,
|
|
@@ -177,10 +174,9 @@ export const makeIdentityLinkingService = () => {
|
|
|
177
174
|
};
|
|
178
175
|
if (type != null)
|
|
179
176
|
credsFilter.type = type;
|
|
180
|
-
const
|
|
181
|
-
if (
|
|
177
|
+
const cred = await credsResource.load(credsFilter);
|
|
178
|
+
if (cred == null)
|
|
182
179
|
return undefined;
|
|
183
|
-
const cred = creds[0];
|
|
184
180
|
const profile = profiles.find(p => p.profileId === cred.profileId) ?? profiles[0];
|
|
185
181
|
return {
|
|
186
182
|
type: cred.type,
|
package/build/service.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.js","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAGpD,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAErD,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owlmeans/server-auth-identity",
|
|
3
|
-
"version": "0.1.18-rc.
|
|
3
|
+
"version": "0.1.18-rc.12",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -22,14 +22,14 @@
|
|
|
22
22
|
}
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@owlmeans/auth": "^0.1.18-rc.
|
|
26
|
-
"@owlmeans/auth-common": "^0.1.18-rc.
|
|
27
|
-
"@owlmeans/basic-ids": "^0.1.18-rc.
|
|
28
|
-
"@owlmeans/context": "^0.1.18-rc.
|
|
29
|
-
"@owlmeans/mongo-resource": "^0.1.18-rc.
|
|
30
|
-
"@owlmeans/oidc": "^0.1.18-rc.
|
|
31
|
-
"@owlmeans/resource": "^0.1.18-rc.
|
|
32
|
-
"@owlmeans/server-context": "^0.1.18-rc.
|
|
25
|
+
"@owlmeans/auth": "^0.1.18-rc.8",
|
|
26
|
+
"@owlmeans/auth-common": "^0.1.18-rc.12",
|
|
27
|
+
"@owlmeans/basic-ids": "^0.1.18-rc.8",
|
|
28
|
+
"@owlmeans/context": "^0.1.18-rc.7",
|
|
29
|
+
"@owlmeans/mongo-resource": "^0.1.18-rc.11",
|
|
30
|
+
"@owlmeans/oidc": "^0.1.18-rc.12",
|
|
31
|
+
"@owlmeans/resource": "^0.1.18-rc.8",
|
|
32
|
+
"@owlmeans/server-context": "^0.1.18-rc.11"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
35
|
"mongodb": "*"
|
package/src/resolver.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { appendContextual } from '@owlmeans/context'
|
|
2
2
|
import type { ServerConfig, ServerContext } from '@owlmeans/server-context'
|
|
3
|
+
import type { Criteria } from '@owlmeans/resource'
|
|
3
4
|
import type { EntityResolverService, OrgEntityRef } from '@owlmeans/auth-common'
|
|
4
5
|
import { ENTITY_RESOLVER, ENTITY_SLUG_PATTERN } from '@owlmeans/auth-common'
|
|
5
6
|
import { generateWordSlug, nextSlugCandidate } from '@owlmeans/basic-ids'
|
|
@@ -18,9 +19,6 @@ type Context = ServerContext<ServerConfig>
|
|
|
18
19
|
*/
|
|
19
20
|
const CACHE_TTL = 30_000
|
|
20
21
|
|
|
21
|
-
/** What a stored record id looks like. Anything else can only be a slug or a frozen key. */
|
|
22
|
-
const RECORD_ID = /^[0-9a-f]{24}$/i
|
|
23
|
-
|
|
24
22
|
/** A stored record as the contract exposes it. Persisted records always carry an id. */
|
|
25
23
|
const toRef = (entity: OrgEntity | null): OrgEntityRef | null =>
|
|
26
24
|
entity == null ? null : {
|
|
@@ -72,18 +70,19 @@ export const makeEntityResolverService = (
|
|
|
72
70
|
|
|
73
71
|
const res = resource()
|
|
74
72
|
// Id first: an id is authoritative, so a slug that happens to look like some other entity's
|
|
75
|
-
// id can never shadow it.
|
|
76
|
-
// frozen key external systems still quote.
|
|
77
|
-
|
|
78
|
-
// The shape test is not an optimisation. `load` reads its argument as a record id, and the
|
|
79
|
-
// store turns that into an ObjectId unconditionally — so handing it a slug throws a driver
|
|
80
|
-
// error out of what is meant to be a lookup that simply misses.
|
|
81
|
-
const byId = RECORD_ID.test(value) ? await res.load(value) : null
|
|
73
|
+
// id can never shadow it. A value that is not a record id simply misses. Then the current
|
|
74
|
+
// slug, then the names it has retired, then the frozen key external systems still quote.
|
|
75
|
+
const byId = await res.load(value)
|
|
82
76
|
if (byId != null) return remember(byId, value)
|
|
83
77
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
78
|
+
const candidates: Criteria<OrgEntity>[] = [
|
|
79
|
+
{ slug: value },
|
|
80
|
+
{ formerSlugs: { $contains: [value] } },
|
|
81
|
+
{ iamKey: value },
|
|
82
|
+
]
|
|
83
|
+
for (const where of candidates) {
|
|
84
|
+
const found = await res.load(where)
|
|
85
|
+
if (found != null) return remember(found, value)
|
|
87
86
|
}
|
|
88
87
|
|
|
89
88
|
return remember(null, value)
|
|
@@ -92,11 +91,7 @@ export const makeEntityResolverService = (
|
|
|
92
91
|
const service: EntityResolverService = appendContextual<EntityResolverService>(alias, {
|
|
93
92
|
resolve: async value => toRef(await load(value)),
|
|
94
93
|
|
|
95
|
-
byId: async id =>
|
|
96
|
-
const entity = RECORD_ID.test(id) ? await resource().load(id) : null
|
|
97
|
-
|
|
98
|
-
return toRef(remember(entity, id))
|
|
99
|
-
},
|
|
94
|
+
byId: async id => toRef(remember(await resource().load(id), id)),
|
|
100
95
|
|
|
101
96
|
mintSlug: async () => {
|
|
102
97
|
const res = resource()
|
|
@@ -107,11 +102,10 @@ export const makeEntityResolverService = (
|
|
|
107
102
|
const base = generateWordSlug()
|
|
108
103
|
for (let suffix = 1; suffix <= 3; ++suffix) {
|
|
109
104
|
const candidate = nextSlugCandidate(base, suffix)
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
pager: { size: 1 },
|
|
105
|
+
const taken = await res.load({
|
|
106
|
+
$or: [{ slug: candidate }, { formerSlugs: { $contains: [candidate] } }],
|
|
113
107
|
})
|
|
114
|
-
if (
|
|
108
|
+
if (taken == null) return candidate
|
|
115
109
|
}
|
|
116
110
|
}
|
|
117
111
|
|
|
@@ -131,10 +125,10 @@ export const makeEntityResolverService = (
|
|
|
131
125
|
|
|
132
126
|
// A slug another entity has ever answered to cannot be taken: tokens and third-party records
|
|
133
127
|
// quoting it would start resolving to the wrong organization.
|
|
134
|
-
const
|
|
135
|
-
|
|
128
|
+
const taken = await res.load({
|
|
129
|
+
$or: [{ slug }, { formerSlugs: { $contains: [slug] } }],
|
|
136
130
|
})
|
|
137
|
-
if (taken
|
|
131
|
+
if (taken != null && taken.id !== id) {
|
|
138
132
|
throw new SyntaxError(`entity:slug-taken:${slug}`)
|
|
139
133
|
}
|
|
140
134
|
|
package/src/resource.ts
CHANGED
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
*/
|
|
18
18
|
export const makeOrgEntityResource = (dbAlias?: string): OrgEntityResource => {
|
|
19
19
|
const resource = makeMongoResource<OrgEntity, OrgEntityResource>(
|
|
20
|
-
AUTH_IDENTITY_ORG_ENTITY, dbAlias, undefined,
|
|
20
|
+
AUTH_IDENTITY_ORG_ENTITY, dbAlias, undefined, AUTH_IDENTITY_ORG_ENTITY_COLLECTION
|
|
21
21
|
)
|
|
22
22
|
resource.index('slug', { slug: 1 }, { unique: true })
|
|
23
23
|
resource.index('iamKey', { iamKey: 1 }, { unique: true })
|
|
@@ -27,7 +27,7 @@ export const makeOrgEntityResource = (dbAlias?: string): OrgEntityResource => {
|
|
|
27
27
|
|
|
28
28
|
export const makeIdentityAccountResource = (dbAlias?: string): IdentityAccountResource => {
|
|
29
29
|
const resource = makeMongoResource<IdentityAccount, IdentityAccountResource>(
|
|
30
|
-
AUTH_IDENTITY_ACCOUNT, dbAlias, undefined,
|
|
30
|
+
AUTH_IDENTITY_ACCOUNT, dbAlias, undefined, AUTH_IDENTITY_ACCOUNT_COLLECTION
|
|
31
31
|
)
|
|
32
32
|
resource.index('credential', { credential: 1 }, { unique: true })
|
|
33
33
|
resource.index('entityId', { entityId: 1 })
|
|
@@ -37,7 +37,7 @@ export const makeIdentityAccountResource = (dbAlias?: string): IdentityAccountRe
|
|
|
37
37
|
|
|
38
38
|
export const makeIdentityProfileResource = (dbAlias?: string): IdentityProfileResource => {
|
|
39
39
|
const resource = makeMongoResource<IdentityProfile, IdentityProfileResource>(
|
|
40
|
-
AUTH_IDENTITY_PROFILE, dbAlias, undefined,
|
|
40
|
+
AUTH_IDENTITY_PROFILE, dbAlias, undefined, AUTH_IDENTITY_PROFILE_COLLECTION
|
|
41
41
|
)
|
|
42
42
|
/**
|
|
43
43
|
* The account's mongo id — the ONLY ObjectId reference in the identity trio.
|
|
@@ -54,7 +54,7 @@ export const makeIdentityProfileResource = (dbAlias?: string): IdentityProfileRe
|
|
|
54
54
|
|
|
55
55
|
export const makeIdentityCredentialsResource = (dbAlias?: string): IdentityCredentialsResource => {
|
|
56
56
|
const resource = makeMongoResource<IdentityCredentials, IdentityCredentialsResource>(
|
|
57
|
-
AUTH_IDENTITY_CREDENTIALS, dbAlias, undefined,
|
|
57
|
+
AUTH_IDENTITY_CREDENTIALS, dbAlias, undefined, AUTH_IDENTITY_CREDENTIALS_COLLECTION
|
|
58
58
|
)
|
|
59
59
|
resource.index('provider', { type: 1, userId: 1, credential: 1 }, { unique: true })
|
|
60
60
|
resource.index('profileId', { profileId: 1 })
|
package/src/service.ts
CHANGED
|
@@ -4,7 +4,9 @@ import type { AuthCredentials, AuthPayload, Profile } from '@owlmeans/auth'
|
|
|
4
4
|
import { ALL_SCOPES, AuthRole } from '@owlmeans/auth'
|
|
5
5
|
import type { ProviderProfileDetails } from '@owlmeans/oidc'
|
|
6
6
|
import { createIdOfLength, IdStyle } from '@owlmeans/basic-ids'
|
|
7
|
+
import type { Criteria } from '@owlmeans/resource'
|
|
7
8
|
import type { AccountMeta, IdentityAccountResource, IdentityProfileResource, IdentityCredentialsResource, IdentityLinkingService } from './types.js'
|
|
9
|
+
import type { IdentityCredentials, IdentityProfile } from './types.js'
|
|
8
10
|
import type { OrgEntity, OrgEntityResource } from './types.js'
|
|
9
11
|
import type { EntityResolverService } from '@owlmeans/auth-common'
|
|
10
12
|
import { ENTITY_RESOLVER } from '@owlmeans/auth-common'
|
|
@@ -43,18 +45,15 @@ export const makeIdentityLinkingService = (): IdentityLinkingService => {
|
|
|
43
45
|
const ctx = service.ctx as Context
|
|
44
46
|
const credsResource = ctx.resource<IdentityCredentialsResource>(AUTH_IDENTITY_CREDENTIALS)
|
|
45
47
|
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
credential: loginService(details),
|
|
51
|
-
}
|
|
48
|
+
const cred = await credsResource.load({
|
|
49
|
+
type: details.type,
|
|
50
|
+
userId: externalKey(details),
|
|
51
|
+
credential: loginService(details),
|
|
52
52
|
})
|
|
53
|
-
const cred = creds[0] ?? null
|
|
54
53
|
if (cred == null) return null
|
|
55
54
|
|
|
56
55
|
const profileResource = ctx.resource<IdentityProfileResource>(AUTH_IDENTITY_PROFILE)
|
|
57
|
-
const profile = await profileResource.load(cred.profileId
|
|
56
|
+
const profile = await profileResource.load({ profileId: cred.profileId })
|
|
58
57
|
if (profile == null) return null
|
|
59
58
|
|
|
60
59
|
return {
|
|
@@ -126,7 +125,7 @@ export const makeIdentityLinkingService = (): IdentityLinkingService => {
|
|
|
126
125
|
})
|
|
127
126
|
} catch (err: any) {
|
|
128
127
|
if (err?.code === 11000 || err?.message?.includes('duplicate')) {
|
|
129
|
-
profile = await profileResource.get(profileId
|
|
128
|
+
profile = await profileResource.get({ profileId })
|
|
130
129
|
} else {
|
|
131
130
|
throw err
|
|
132
131
|
}
|
|
@@ -174,7 +173,7 @@ export const makeIdentityLinkingService = (): IdentityLinkingService => {
|
|
|
174
173
|
getOwnerProfiles: async (entityId: string): Promise<Profile[]> => {
|
|
175
174
|
const ctx = service.ctx as Context
|
|
176
175
|
const profileResource = ctx.resource<IdentityProfileResource>(AUTH_IDENTITY_PROFILE)
|
|
177
|
-
const { items: profiles } = await profileResource.list({
|
|
176
|
+
const { items: profiles } = await profileResource.list({ entityId })
|
|
178
177
|
|
|
179
178
|
return await Promise.all(profiles.map(async p => ({
|
|
180
179
|
id: p.profileId,
|
|
@@ -193,19 +192,18 @@ export const makeIdentityLinkingService = (): IdentityLinkingService => {
|
|
|
193
192
|
const profileResource = ctx.resource<IdentityProfileResource>(AUTH_IDENTITY_PROFILE)
|
|
194
193
|
const credsResource = ctx.resource<IdentityCredentialsResource>(AUTH_IDENTITY_CREDENTIALS)
|
|
195
194
|
|
|
196
|
-
const profileFilter:
|
|
195
|
+
const profileFilter: Criteria<IdentityProfile> = { userId }
|
|
197
196
|
if (entityId != null) profileFilter.entityId = entityId
|
|
198
|
-
const { items: profiles } = await profileResource.list(profileFilter
|
|
197
|
+
const { items: profiles } = await profileResource.list(profileFilter)
|
|
199
198
|
if (profiles.length === 0) return undefined
|
|
200
199
|
|
|
201
|
-
const credsFilter:
|
|
200
|
+
const credsFilter: Criteria<IdentityCredentials> = {
|
|
202
201
|
profileId: { $in: profiles.map(p => p.profileId) }
|
|
203
202
|
}
|
|
204
203
|
if (type != null) credsFilter.type = type
|
|
205
|
-
const
|
|
206
|
-
if (
|
|
204
|
+
const cred = await credsResource.load(credsFilter)
|
|
205
|
+
if (cred == null) return undefined
|
|
207
206
|
|
|
208
|
-
const cred = creds[0]
|
|
209
207
|
const profile = profiles.find(p => p.profileId === cred.profileId) ?? profiles[0]
|
|
210
208
|
|
|
211
209
|
return {
|