@ballistix.digital/identity-connector 0.0.0-local

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.
Files changed (71) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +631 -0
  3. package/dist/common/domain/enum/identityConnectorExceptionType.enum.d.ts +14 -0
  4. package/dist/common/domain/enum/identityConnectorExceptionType.enum.js +18 -0
  5. package/dist/common/domain/model/identity.d.ts +9 -0
  6. package/dist/common/domain/model/identity.js +2 -0
  7. package/dist/common/domain/model/identityProfile.d.ts +6 -0
  8. package/dist/common/domain/model/identityProfile.js +2 -0
  9. package/dist/index.d.ts +12 -0
  10. package/dist/index.js +23 -0
  11. package/dist/module/entra/domain/model/entraProviderOptions.d.ts +6 -0
  12. package/dist/module/entra/domain/model/entraProviderOptions.js +42 -0
  13. package/dist/module/entra/index.d.ts +2 -0
  14. package/dist/module/entra/index.js +7 -0
  15. package/dist/module/entra/service/entra.provider.d.ts +23 -0
  16. package/dist/module/entra/service/entra.provider.js +72 -0
  17. package/dist/module/identity/domain/exception/identityConnectorException.d.ts +5 -0
  18. package/dist/module/identity/domain/exception/identityConnectorException.js +48 -0
  19. package/dist/module/identity/domain/model/identityConnectorModuleOptions.d.ts +7 -0
  20. package/dist/module/identity/domain/model/identityConnectorModuleOptions.js +2 -0
  21. package/dist/module/identity/domain/model/identityProvider.d.ts +22 -0
  22. package/dist/module/identity/domain/model/identityProvider.js +17 -0
  23. package/dist/module/identity/domain/model/identityProviderOptions.d.ts +5 -0
  24. package/dist/module/identity/domain/model/identityProviderOptions.js +34 -0
  25. package/dist/module/identity/domain/model/identityProvidersToken.d.ts +1 -0
  26. package/dist/module/identity/domain/model/identityProvidersToken.js +4 -0
  27. package/dist/module/identity/domain/model/userStore.d.ts +10 -0
  28. package/dist/module/identity/domain/model/userStore.js +12 -0
  29. package/dist/module/identity/domain/validation/default.decorator.d.ts +1 -0
  30. package/dist/module/identity/domain/validation/default.decorator.js +10 -0
  31. package/dist/module/identity/domain/validation/trimmed.decorator.d.ts +2 -0
  32. package/dist/module/identity/domain/validation/trimmed.decorator.js +17 -0
  33. package/dist/module/identity/domain/validation/validateOptions.d.ts +2 -0
  34. package/dist/module/identity/domain/validation/validateOptions.js +44 -0
  35. package/dist/module/identity/identityConnector.module.d.ts +6 -0
  36. package/dist/module/identity/identityConnector.module.js +47 -0
  37. package/dist/module/identity/service/identityAuth.guard.d.ts +20 -0
  38. package/dist/module/identity/service/identityAuth.guard.js +117 -0
  39. package/dist/module/identity/service/identityManagement.d.ts +16 -0
  40. package/dist/module/identity/service/identityManagement.js +54 -0
  41. package/dist/module/identity/service/identityRuntime.d.ts +2 -0
  42. package/dist/module/identity/service/identityRuntime.js +6 -0
  43. package/dist/module/identity/service/identityRuntimeInternals.d.ts +11 -0
  44. package/dist/module/identity/service/identityRuntimeInternals.js +52 -0
  45. package/dist/module/identity/service/signIn.cache.d.ts +20 -0
  46. package/dist/module/identity/service/signIn.cache.js +102 -0
  47. package/dist/module/jwt/service/signedToken.verifier.d.ts +12 -0
  48. package/dist/module/jwt/service/signedToken.verifier.js +56 -0
  49. package/dist/module/zitadel/domain/model/zitadelManagementOptions.d.ts +4 -0
  50. package/dist/module/zitadel/domain/model/zitadelManagementOptions.js +31 -0
  51. package/dist/module/zitadel/domain/model/zitadelProviderOptions.d.ts +10 -0
  52. package/dist/module/zitadel/domain/model/zitadelProviderOptions.js +48 -0
  53. package/dist/module/zitadel/domain/model/zitadelServiceUserKey.d.ts +6 -0
  54. package/dist/module/zitadel/domain/model/zitadelServiceUserKey.js +42 -0
  55. package/dist/module/zitadel/domain/validation/isRsaPrivateKey.decorator.d.ts +2 -0
  56. package/dist/module/zitadel/domain/validation/isRsaPrivateKey.decorator.js +26 -0
  57. package/dist/module/zitadel/domain/validation/organizationIdList.decorator.d.ts +1 -0
  58. package/dist/module/zitadel/domain/validation/organizationIdList.decorator.js +19 -0
  59. package/dist/module/zitadel/index.d.ts +4 -0
  60. package/dist/module/zitadel/index.js +11 -0
  61. package/dist/module/zitadel/service/zitadel.provider.d.ts +40 -0
  62. package/dist/module/zitadel/service/zitadel.provider.js +266 -0
  63. package/dist/testing/index.d.ts +2 -0
  64. package/dist/testing/index.js +7 -0
  65. package/dist/testing/service/testIdentityProvider.mock.d.ts +42 -0
  66. package/dist/testing/service/testIdentityProvider.mock.js +118 -0
  67. package/dist/testing/service/userStore.contract.d.ts +17 -0
  68. package/dist/testing/service/userStore.contract.js +156 -0
  69. package/dist/types/index.d.ts +1 -0
  70. package/dist/types/index.js +5 -0
  71. package/package.json +139 -0
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.userStoreContract = userStoreContract;
7
+ const assert_1 = __importDefault(require("assert"));
8
+ const crypto_1 = require("crypto");
9
+ const identityConnectorExceptionType_enum_1 = require("../../common/domain/enum/identityConnectorExceptionType.enum");
10
+ const identityConnectorException_1 = require("../../module/identity/domain/exception/identityConnectorException");
11
+ function userStoreContract(fixture) {
12
+ const identityId = () => `contract-${(0, crypto_1.randomUUID)()}`;
13
+ const sample = () => ({ email: `contract-${(0, crypto_1.randomUUID)()}@example.com`, givenName: 'Contract', familyName: 'User' });
14
+ return [
15
+ {
16
+ name: 'creates one user for an identity, however often create runs for it',
17
+ run: async () => {
18
+ const { store, providers, userId } = await fixture();
19
+ const { email, givenName, familyName } = sample();
20
+ const identity = {
21
+ provider: providers[0],
22
+ id: identityId(),
23
+ email,
24
+ emailVerified: true,
25
+ givenName,
26
+ familyName,
27
+ roles: [],
28
+ };
29
+ const [first, second] = await Promise.all([store.create(identity), store.create(identity)]);
30
+ if (first === null && second === null) {
31
+ return;
32
+ }
33
+ assert_1.default.notStrictEqual(first, null);
34
+ assert_1.default.strictEqual(userId(second), userId(first));
35
+ assert_1.default.strictEqual(userId((await store.findByIdentityId(identity.id, identity.provider))), userId(first));
36
+ },
37
+ },
38
+ {
39
+ name: 'finds no user for an identity nobody is linked to',
40
+ run: async () => {
41
+ const { store, providers } = await fixture();
42
+ assert_1.default.strictEqual(await store.findByIdentityId(identityId(), providers[0]), null);
43
+ },
44
+ },
45
+ {
46
+ name: 'links a user without an identity, and finds the user by that identity afterwards',
47
+ run: async () => {
48
+ const { store, providers, createUser, userId } = await fixture();
49
+ const user = await createUser(sample());
50
+ const id = identityId();
51
+ assert_1.default.strictEqual(await store.link(user, id, providers[0]), true);
52
+ assert_1.default.strictEqual(userId((await store.findByIdentityId(id, providers[0]))), userId(user));
53
+ },
54
+ },
55
+ {
56
+ name: 'links a user to the identity it already has again',
57
+ run: async () => {
58
+ const { store, providers, createUser } = await fixture();
59
+ const user = await createUser(sample());
60
+ const id = identityId();
61
+ await store.link(user, id, providers[0]);
62
+ assert_1.default.strictEqual(await store.link(user, id, providers[0]), true);
63
+ },
64
+ },
65
+ {
66
+ name: 'refuses to link a user that already has another identity of the same provider',
67
+ run: async () => {
68
+ const { store, providers, createUser, userId } = await fixture();
69
+ const user = await createUser(sample());
70
+ const first = identityId();
71
+ const second = identityId();
72
+ await store.link(user, first, providers[0]);
73
+ assert_1.default.strictEqual(await store.link(user, second, providers[0]), false);
74
+ assert_1.default.strictEqual(userId((await store.findByIdentityId(first, providers[0]))), userId(user));
75
+ assert_1.default.strictEqual(await store.findByIdentityId(second, providers[0]), null);
76
+ },
77
+ },
78
+ {
79
+ name: 'refuses to link an identity another user has',
80
+ run: async () => {
81
+ const { store, providers, createUser, userId } = await fixture();
82
+ const owner = await createUser(sample());
83
+ const other = await createUser(sample());
84
+ const id = identityId();
85
+ assert_1.default.strictEqual(await store.link(owner, id, providers[0]), true);
86
+ assert_1.default.strictEqual(await store.link(other, id, providers[0]), false);
87
+ assert_1.default.strictEqual(userId((await store.findByIdentityId(id, providers[0]))), userId(owner));
88
+ },
89
+ },
90
+ {
91
+ name: 'links a copy of a user, loaded on its own, to the identity the user has',
92
+ run: async () => {
93
+ const { store, providers, createUser, userId } = await fixture();
94
+ const user = await createUser(sample());
95
+ const id = identityId();
96
+ assert_1.default.strictEqual(await store.link(user, id, providers[0]), true);
97
+ const copy = (await store.findByIdentityId(id, providers[0]));
98
+ assert_1.default.strictEqual(await store.link(copy, id, providers[0]), true);
99
+ assert_1.default.strictEqual(userId((await store.findByIdentityId(id, providers[0]))), userId(user));
100
+ },
101
+ },
102
+ {
103
+ name: 'links an identity to one user only when two users link it at once',
104
+ run: async () => {
105
+ const { store, providers, createUser, userId } = await fixture();
106
+ const first = await createUser(sample());
107
+ const second = await createUser(sample());
108
+ const id = identityId();
109
+ const linked = await Promise.all([store.link(first, id, providers[0]), store.link(second, id, providers[0])]);
110
+ assert_1.default.deepStrictEqual(linked.filter((wasLinked) => wasLinked), [true]);
111
+ const owner = linked[0] ? first : second;
112
+ assert_1.default.strictEqual(userId((await store.findByIdentityId(id, providers[0]))), userId(owner));
113
+ },
114
+ },
115
+ {
116
+ name: 'gives the provider a profile with the identity id once the user is linked',
117
+ run: async () => {
118
+ const { store, providers, createUser } = await fixture();
119
+ const values = sample();
120
+ const user = await createUser(values);
121
+ const id = identityId();
122
+ assert_1.default.deepStrictEqual(store.toProfile(user, providers[0]), { identityId: null, ...values });
123
+ await store.link(user, id, providers[0]);
124
+ const linked = (await store.findByIdentityId(id, providers[0]));
125
+ assert_1.default.deepStrictEqual(store.toProfile(linked, providers[0]), { identityId: id, ...values });
126
+ },
127
+ },
128
+ {
129
+ name: 'throws NO_EMAIL for the profile of a user without an email',
130
+ run: async () => {
131
+ const { store, providers, createUser, usersWithoutEmail = true } = await fixture();
132
+ if (!usersWithoutEmail) {
133
+ return;
134
+ }
135
+ const user = await createUser({ ...sample(), email: null });
136
+ assert_1.default.throws(() => store.toProfile(user, providers[0]), (error) => (0, identityConnectorException_1.identityConnectorExceptionTypeOf)(error) === identityConnectorExceptionType_enum_1.IdentityConnectorExceptionTypeEnum.NO_EMAIL);
137
+ },
138
+ },
139
+ {
140
+ name: 'keeps the identities of two providers apart',
141
+ run: async () => {
142
+ const { store, providers, createUser, userId } = await fixture();
143
+ if (providers.length < 2) {
144
+ return;
145
+ }
146
+ const [first, second] = providers;
147
+ const user = await createUser(sample());
148
+ const id = identityId();
149
+ await store.link(user, id, first);
150
+ assert_1.default.strictEqual(await store.findByIdentityId(id, second), null);
151
+ assert_1.default.strictEqual(await store.link(user, identityId(), second), true);
152
+ assert_1.default.strictEqual(userId((await store.findByIdentityId(id, first))), userId(user));
153
+ },
154
+ },
155
+ ];
156
+ }
@@ -0,0 +1 @@
1
+ export { IdentityConnectorExceptionTypeEnum } from '../common/domain/enum/identityConnectorExceptionType.enum';
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.IdentityConnectorExceptionTypeEnum = void 0;
4
+ var identityConnectorExceptionType_enum_1 = require("../common/domain/enum/identityConnectorExceptionType.enum");
5
+ Object.defineProperty(exports, "IdentityConnectorExceptionTypeEnum", { enumerable: true, get: function () { return identityConnectorExceptionType_enum_1.IdentityConnectorExceptionTypeEnum; } });
package/package.json ADDED
@@ -0,0 +1,139 @@
1
+ {
2
+ "name": "@ballistix.digital/identity-connector",
3
+ "version": "0.0.0-local",
4
+ "description": "NestJS module that signs a user in with an OIDC access token and provisions users at one or more identity providers, behind provider-agnostic contracts.",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/layeredprints/identity-connector.git"
9
+ },
10
+ "publishConfig": {
11
+ "access": "public"
12
+ },
13
+ "engines": {
14
+ "node": ">=24"
15
+ },
16
+ "main": "dist/index.js",
17
+ "types": "dist/index.d.ts",
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "default": "./dist/index.js"
22
+ },
23
+ "./zitadel": {
24
+ "types": "./dist/module/zitadel/index.d.ts",
25
+ "default": "./dist/module/zitadel/index.js"
26
+ },
27
+ "./entra": {
28
+ "types": "./dist/module/entra/index.d.ts",
29
+ "default": "./dist/module/entra/index.js"
30
+ },
31
+ "./testing": {
32
+ "types": "./dist/testing/index.d.ts",
33
+ "default": "./dist/testing/index.js"
34
+ },
35
+ "./types": {
36
+ "types": "./dist/types/index.d.ts",
37
+ "default": "./dist/types/index.js"
38
+ },
39
+ "./dist/*": {
40
+ "types": "./dist/*.d.ts",
41
+ "default": "./dist/*.js"
42
+ }
43
+ },
44
+ "typesVersions": {
45
+ "*": {
46
+ "zitadel": [
47
+ "dist/module/zitadel/index.d.ts"
48
+ ],
49
+ "entra": [
50
+ "dist/module/entra/index.d.ts"
51
+ ],
52
+ "testing": [
53
+ "dist/testing/index.d.ts"
54
+ ],
55
+ "types": [
56
+ "dist/types/index.d.ts"
57
+ ]
58
+ }
59
+ },
60
+ "files": [
61
+ "dist",
62
+ "CHANGELOG.md"
63
+ ],
64
+ "scripts": {
65
+ "build": "rm -rf dist && tsc -p tsconfig.build.json",
66
+ "lint": "eslint \"src/**/*.ts\" \"test/**/*.ts\"",
67
+ "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
68
+ "test": "jest --selectProjects unit",
69
+ "test:unit": "jest --selectProjects unit",
70
+ "test:packaging": "npm run build && jest --selectProjects packaging",
71
+ "test:watch": "jest --selectProjects unit --watch",
72
+ "test:coverage": "jest --selectProjects unit --coverage"
73
+ },
74
+ "peerDependencies": {
75
+ "@ballistix.digital/exception-mapper": ">=0.8.0 <1.0.0",
76
+ "@ballistix.digital/exception-types": ">=0.8.0 <1.0.0",
77
+ "@nestjs/common": "^11 || ^12",
78
+ "@nestjs/core": "^11 || ^12",
79
+ "class-transformer": "^0.5.1",
80
+ "class-validator": "^0.15.1",
81
+ "jose": "^6",
82
+ "reflect-metadata": "^0.2"
83
+ },
84
+ "peerDependenciesMeta": {
85
+ "@ballistix.digital/exception-mapper": {
86
+ "optional": true
87
+ },
88
+ "@ballistix.digital/exception-types": {
89
+ "optional": true
90
+ },
91
+ "@nestjs/common": {
92
+ "optional": true
93
+ },
94
+ "@nestjs/core": {
95
+ "optional": true
96
+ },
97
+ "class-transformer": {
98
+ "optional": true
99
+ },
100
+ "class-validator": {
101
+ "optional": true
102
+ },
103
+ "jose": {
104
+ "optional": true
105
+ },
106
+ "reflect-metadata": {
107
+ "optional": true
108
+ }
109
+ },
110
+ "devDependencies": {
111
+ "@ballistix.digital/exception-mapper": "^0.8.0",
112
+ "@ballistix.digital/exception-types": "^0.8.0",
113
+ "@nestjs/common": "^11.1.6",
114
+ "@nestjs/core": "^11.1.6",
115
+ "@nestjs/swagger": "^11.0.6",
116
+ "@nestjs/testing": "^11.1.6",
117
+ "@types/jest": "^30.0.0",
118
+ "@types/jsonwebtoken": "^9.0.10",
119
+ "@types/node": "^24.19.2",
120
+ "@typescript-eslint/eslint-plugin": "^8.44.0",
121
+ "@typescript-eslint/parser": "^8.44.0",
122
+ "class-transformer": "^0.5.1",
123
+ "class-validator": "0.15.1",
124
+ "eslint": "^8.57.1",
125
+ "eslint-config-prettier": "^9.1.0",
126
+ "eslint-plugin-prettier": "^5.5.0",
127
+ "jest": "^30.0.0",
128
+ "jose": "^6.2.13",
129
+ "jsonwebtoken": "^9.0.3",
130
+ "lodash": "^4.17.21",
131
+ "luxon": "^3.7.2",
132
+ "prettier": "^3.6.0",
133
+ "reflect-metadata": "^0.2.2",
134
+ "rxjs": "^7.8.2",
135
+ "ts-jest": "^29.4.0",
136
+ "typeorm": "^1.1.0",
137
+ "typescript": "^5.9.0"
138
+ }
139
+ }