jinaga-server 1.0.0

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 (127) hide show
  1. package/LICENSE +22 -0
  2. package/dist/authentication/authentication-device.d.ts +20 -0
  3. package/dist/authentication/authentication-device.js +61 -0
  4. package/dist/authentication/authentication-device.js.map +1 -0
  5. package/dist/authentication/authentication-impl.d.ts +21 -0
  6. package/dist/authentication/authentication-impl.js +61 -0
  7. package/dist/authentication/authentication-impl.js.map +1 -0
  8. package/dist/authentication/authentication-session.d.ts +23 -0
  9. package/dist/authentication/authentication-session.js +85 -0
  10. package/dist/authentication/authentication-session.js.map +1 -0
  11. package/dist/authentication/authentication.d.ts +5 -0
  12. package/dist/authentication/authentication.js +3 -0
  13. package/dist/authentication/authentication.js.map +1 -0
  14. package/dist/authentication.d.ts +17 -0
  15. package/dist/authentication.js +52 -0
  16. package/dist/authentication.js.map +1 -0
  17. package/dist/authorization/authorization-keystore.d.ts +13 -0
  18. package/dist/authorization/authorization-keystore.js +61 -0
  19. package/dist/authorization/authorization-keystore.js.map +1 -0
  20. package/dist/http/node-http.d.ts +7 -0
  21. package/dist/http/node-http.js +126 -0
  22. package/dist/http/node-http.js.map +1 -0
  23. package/dist/http/router.d.ts +20 -0
  24. package/dist/http/router.js +223 -0
  25. package/dist/http/router.js.map +1 -0
  26. package/dist/index.d.ts +1 -0
  27. package/dist/index.js +6 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/jinaga-server.d.ts +18 -0
  30. package/dist/jinaga-server.js +101 -0
  31. package/dist/jinaga-server.js.map +1 -0
  32. package/dist/keystore.d.ts +9 -0
  33. package/dist/keystore.js +3 -0
  34. package/dist/keystore.js.map +1 -0
  35. package/dist/memory/memory-keystore.d.ts +16 -0
  36. package/dist/memory/memory-keystore.js +86 -0
  37. package/dist/memory/memory-keystore.js.map +1 -0
  38. package/dist/postgres/connection.d.ts +12 -0
  39. package/dist/postgres/connection.js +83 -0
  40. package/dist/postgres/connection.js.map +1 -0
  41. package/dist/postgres/edge-record.d.ts +9 -0
  42. package/dist/postgres/edge-record.js +30 -0
  43. package/dist/postgres/edge-record.js.map +1 -0
  44. package/dist/postgres/maps.d.ts +21 -0
  45. package/dist/postgres/maps.js +86 -0
  46. package/dist/postgres/maps.js.map +1 -0
  47. package/dist/postgres/postgres-keystore.d.ts +20 -0
  48. package/dist/postgres/postgres-keystore.js +168 -0
  49. package/dist/postgres/postgres-keystore.js.map +1 -0
  50. package/dist/postgres/postgres-store.d.ts +20 -0
  51. package/dist/postgres/postgres-store.js +717 -0
  52. package/dist/postgres/postgres-store.js.map +1 -0
  53. package/dist/postgres/query-description-builder.d.ts +13 -0
  54. package/dist/postgres/query-description-builder.js +104 -0
  55. package/dist/postgres/query-description-builder.js.map +1 -0
  56. package/dist/postgres/query-description.d.ts +71 -0
  57. package/dist/postgres/query-description.js +256 -0
  58. package/dist/postgres/query-description.js.map +1 -0
  59. package/dist/postgres/specification-result-sql.d.ts +41 -0
  60. package/dist/postgres/specification-result-sql.js +260 -0
  61. package/dist/postgres/specification-result-sql.js.map +1 -0
  62. package/dist/postgres/specification-sql.d.ts +3 -0
  63. package/dist/postgres/specification-sql.js +119 -0
  64. package/dist/postgres/specification-sql.js.map +1 -0
  65. package/dist/postgres/sql.d.ts +10 -0
  66. package/dist/postgres/sql.js +396 -0
  67. package/dist/postgres/sql.js.map +1 -0
  68. package/dist/util/fn.d.ts +6 -0
  69. package/dist/util/fn.js +81 -0
  70. package/dist/util/fn.js.map +1 -0
  71. package/dist/util/promise.d.ts +1 -0
  72. package/dist/util/promise.js +10 -0
  73. package/dist/util/promise.js.map +1 -0
  74. package/docs/registrations.sql +22 -0
  75. package/docs/specification.txt +41 -0
  76. package/docs/sql-generator.gv +25 -0
  77. package/integration-test/docker-compose.yaml +13 -0
  78. package/integration-test/jinaga-test/Dockerfile +12 -0
  79. package/integration-test/jinaga-test/jinaga.test.js +425 -0
  80. package/integration-test/jinaga-test/package-lock.json +6767 -0
  81. package/integration-test/jinaga-test/package.json +25 -0
  82. package/integration-test/postgres/0-init-app-db.sh +16 -0
  83. package/integration-test/postgres/1-setup.sql +219 -0
  84. package/integration-test/postgres/2-grant.sh +17 -0
  85. package/integration-test/postgres/Dockerfile +5 -0
  86. package/integration-test/run.sh +17 -0
  87. package/integration-test/start_db.sh +2 -0
  88. package/integration-test/stop_db.sh +3 -0
  89. package/integration-test/test.sh +8 -0
  90. package/interactive/index.js +56 -0
  91. package/jest.config.js +12 -0
  92. package/package.json +51 -0
  93. package/scripts/combined.sql +46 -0
  94. package/scripts/cte.sql +55 -0
  95. package/scripts/separate.sql +27 -0
  96. package/setup.sh +34 -0
  97. package/setup.sql +329 -0
  98. package/src/authentication/authentication-device.ts +68 -0
  99. package/src/authentication/authentication-impl.ts +59 -0
  100. package/src/authentication/authentication-session.ts +95 -0
  101. package/src/authentication/authentication.ts +6 -0
  102. package/src/authentication.ts +45 -0
  103. package/src/authorization/authorization-keystore.ts +67 -0
  104. package/src/http/node-http.ts +106 -0
  105. package/src/http/router.ts +237 -0
  106. package/src/index.ts +1 -0
  107. package/src/jinaga-server.ts +125 -0
  108. package/src/keystore.ts +10 -0
  109. package/src/memory/memory-keystore.ts +93 -0
  110. package/src/postgres/connection.ts +73 -0
  111. package/src/postgres/edge-record.ts +36 -0
  112. package/src/postgres/maps.ts +89 -0
  113. package/src/postgres/postgres-keystore.ts +167 -0
  114. package/src/postgres/postgres-store.ts +874 -0
  115. package/src/postgres/query-description-builder.ts +116 -0
  116. package/src/postgres/query-description.ts +385 -0
  117. package/src/postgres/specification-result-sql.ts +362 -0
  118. package/src/postgres/specification-sql.ts +138 -0
  119. package/src/postgres/sql.ts +482 -0
  120. package/src/util/fn.ts +63 -0
  121. package/src/util/promise.ts +5 -0
  122. package/test/authorization/authorizationSpec.ts +209 -0
  123. package/test/postgres/postgresSpec.ts +385 -0
  124. package/test/postgres/postgresSpecificationSpec.ts +742 -0
  125. package/test/reporter.js +25 -0
  126. package/tsconfig.json +25 -0
  127. package/upgrade.sh +21 -0
package/setup.sql ADDED
@@ -0,0 +1,329 @@
1
+ --
2
+ -- Create tables for a Jinaga database
3
+ --
4
+ -- Before executing, be sure you have created the database and the dev role.
5
+ --
6
+ -- CREATE DATABASE myapplication;
7
+ -- \connect myapplication
8
+ --
9
+ -- CREATE USER dev WITH
10
+ -- LOGIN
11
+ -- ENCRYPTED PASSWORD 'devpassword'
12
+ -- NOSUPERUSER
13
+ -- INHERIT
14
+ -- NOCREATEDB
15
+ -- NOCREATEROLE
16
+ -- NOREPLICATION
17
+ -- VALID UNTIL 'infinity';
18
+ --
19
+
20
+ -- \set appdatabase `echo "$APP_DATABASE"`
21
+
22
+ -- \connect :appdatabase
23
+
24
+ DO
25
+ $do$
26
+ BEGIN
27
+
28
+ CREATE EXTENSION IF NOT EXISTS intarray;
29
+
30
+ IF ((SELECT to_regclass('public.ancestor') IS NULL) AND
31
+ (SELECT to_regclass('public.fact') IS NOT NULL)) THEN
32
+
33
+ -- Move the legacy tables to the legacy schema
34
+
35
+ CREATE SCHEMA legacy;
36
+
37
+ ALTER TABLE public.edge
38
+ SET SCHEMA legacy;
39
+
40
+ ALTER TABLE public.fact
41
+ SET SCHEMA legacy;
42
+
43
+ ALTER TABLE public.signature
44
+ SET SCHEMA legacy;
45
+
46
+ ALTER TABLE public."user"
47
+ SET SCHEMA legacy;
48
+
49
+ END IF;
50
+
51
+ --
52
+ -- Fact Type
53
+ --
54
+
55
+ IF (SELECT to_regclass('public.fact_type')) IS NULL THEN
56
+
57
+ CREATE TABLE fact_type (
58
+ fact_type_id serial PRIMARY KEY,
59
+ name character varying(50) NOT NULL
60
+ );
61
+
62
+
63
+ ALTER TABLE public.fact_type OWNER TO postgres;
64
+
65
+ CREATE UNIQUE INDEX ux_fact_type ON fact_type (name);
66
+
67
+ END IF;
68
+
69
+ --
70
+ -- Role
71
+ --
72
+
73
+ IF (SELECT to_regclass('public.role')) IS NULL THEN
74
+
75
+ CREATE TABLE role (
76
+ role_id serial PRIMARY KEY,
77
+ defining_fact_type_id integer NOT NULL,
78
+ CONSTRAINT fk_defining_fact_type_id
79
+ FOREIGN KEY (defining_fact_type_id)
80
+ REFERENCES fact_type (fact_type_id),
81
+ name character varying(20) NOT NULL
82
+ );
83
+
84
+
85
+ ALTER TABLE public.role OWNER TO postgres;
86
+
87
+ CREATE UNIQUE INDEX ux_role ON public.role USING btree (defining_fact_type_id, name);
88
+
89
+ END IF;
90
+
91
+ --
92
+ -- Fact
93
+ --
94
+
95
+ IF (SELECT to_regclass('public.fact') IS NULL) THEN
96
+
97
+ CREATE TABLE public.fact (
98
+ fact_id SERIAL PRIMARY KEY,
99
+ fact_type_id integer NOT NULL,
100
+ CONSTRAINT fk_fact_type_id
101
+ FOREIGN KEY (fact_type_id)
102
+ REFERENCES fact_type (fact_type_id),
103
+ hash character varying(100),
104
+ data jsonb,
105
+ date_learned timestamp NOT NULL
106
+ DEFAULT (now() at time zone 'utc')
107
+ );
108
+
109
+
110
+ ALTER TABLE public.fact OWNER TO postgres;
111
+
112
+ CREATE UNIQUE INDEX ux_fact ON public.fact USING btree (hash, fact_type_id);
113
+
114
+ END IF;
115
+
116
+ --
117
+ -- Edge
118
+ --
119
+
120
+ IF (SELECT to_regclass('public.edge') IS NULL) THEN
121
+
122
+ CREATE TABLE public.edge (
123
+ role_id integer NOT NULL,
124
+ CONSTRAINT fk_role_id
125
+ FOREIGN KEY (role_id)
126
+ REFERENCES role (role_id),
127
+ successor_fact_id integer NOT NULL,
128
+ CONSTRAINT fk_successor_fact_id
129
+ FOREIGN KEY (successor_fact_id)
130
+ REFERENCES fact (fact_id),
131
+ predecessor_fact_id integer NOT NULL,
132
+ CONSTRAINT fk_predecessor_fact_id
133
+ FOREIGN KEY (predecessor_fact_id)
134
+ REFERENCES fact (fact_id)
135
+ );
136
+
137
+
138
+ ALTER TABLE public.edge OWNER TO postgres;
139
+
140
+ -- Most unique first, for fastest uniqueness check on insert.
141
+ CREATE UNIQUE INDEX ux_edge ON public.edge USING btree (successor_fact_id, predecessor_fact_id, role_id);
142
+ -- Covering index based on successor, favoring most likely members of WHERE clause.
143
+ CREATE INDEX ix_successor ON public.edge USING btree (successor_fact_id, role_id, predecessor_fact_id);
144
+ -- Covering index based on predecessor, favoring most likely members of WHERE clause.
145
+ CREATE INDEX ix_predecessor ON public.edge USING btree (predecessor_fact_id, role_id, successor_fact_id);
146
+
147
+ END IF;
148
+
149
+ --
150
+ -- Ancestor
151
+ --
152
+
153
+ IF (SELECT to_regclass('public.ancestor') IS NULL) THEN
154
+
155
+ CREATE TABLE public.ancestor (
156
+ fact_id integer NOT NULL,
157
+ CONSTRAINT fk_fact_id
158
+ FOREIGN KEY (fact_id)
159
+ REFERENCES fact (fact_id),
160
+ ancestor_fact_id integer NOT NULL,
161
+ CONSTRAINT fk_ancestor_fact_id
162
+ FOREIGN KEY (ancestor_fact_id)
163
+ REFERENCES fact (fact_id)
164
+ );
165
+
166
+
167
+ ALTER TABLE public.ancestor OWNER TO postgres;
168
+
169
+ CREATE UNIQUE INDEX ux_ancestor ON public.ancestor USING btree (fact_id, ancestor_fact_id);
170
+
171
+ END IF;
172
+
173
+ --
174
+ -- Public Key
175
+ --
176
+
177
+ IF (SELECT to_regclass('public.public_key') IS NULL) THEN
178
+
179
+ CREATE TABLE public.public_key (
180
+ public_key_id serial PRIMARY KEY,
181
+ public_key character varying(500) NOT NULL
182
+ );
183
+
184
+
185
+ ALTER TABLE public.public_key OWNER TO postgres;
186
+
187
+ CREATE UNIQUE INDEX ux_public_key ON public.public_key (public_key);
188
+
189
+ END IF;
190
+
191
+ --
192
+ -- Signature
193
+ --
194
+
195
+ IF (SELECT to_regclass('public.signature') IS NULL) THEN
196
+
197
+ CREATE TABLE public."signature" (
198
+ fact_id integer NOT NULL,
199
+ CONSTRAINT fk_fact_id
200
+ FOREIGN KEY (fact_id)
201
+ REFERENCES fact (fact_id),
202
+ public_key_id integer NOT NULL,
203
+ CONSTRAINT fk_public_key_id
204
+ FOREIGN KEY (public_key_id)
205
+ REFERENCES public_key (public_key_id),
206
+ signature character varying(400),
207
+ date_learned timestamp NOT NULL
208
+ DEFAULT (now() at time zone 'utc')
209
+ );
210
+
211
+
212
+ ALTER TABLE public."signature" OWNER TO postgres;
213
+
214
+ CREATE UNIQUE INDEX ux_signature ON public."signature" USING btree (fact_id, public_key_id);
215
+
216
+ END IF;
217
+
218
+ --
219
+ -- User
220
+ --
221
+
222
+ IF (SELECT to_regclass('public.user') IS NULL) THEN
223
+
224
+ CREATE TABLE public."user" (
225
+ provider character varying(100),
226
+ user_identifier character varying(50),
227
+ private_key character varying(1800),
228
+ public_key character varying(500)
229
+ );
230
+
231
+
232
+ ALTER TABLE public."user" OWNER TO postgres;
233
+
234
+ CREATE UNIQUE INDEX ux_user ON public."user" USING btree (user_identifier, provider);
235
+ CREATE UNIQUE INDEX ux_user_public_key ON public."user" (public_key);
236
+
237
+ END IF;
238
+
239
+ IF (SELECT to_regclass('legacy.fact') IS NOT NULL) THEN
240
+
241
+ INSERT INTO public."user"
242
+ (provider, user_identifier, private_key, public_key)
243
+ SELECT provider, user_id, private_key, public_key
244
+ FROM legacy."user"
245
+ ON CONFLICT DO NOTHING;
246
+
247
+ INSERT INTO public.fact_type
248
+ (name)
249
+ SELECT DISTINCT type
250
+ FROM legacy.fact
251
+ WHERE type IS NOT NULL
252
+ ON CONFLICT DO NOTHING;
253
+
254
+ INSERT INTO public.role
255
+ (defining_fact_type_id, name)
256
+ SELECT DISTINCT f.fact_type_id, e.role
257
+ FROM legacy.edge e
258
+ JOIN public.fact_type f
259
+ ON f.name = e.successor_type
260
+ ON CONFLICT DO NOTHING;
261
+
262
+ INSERT INTO public.fact
263
+ (fact_type_id, hash, data, date_learned)
264
+ SELECT
265
+ t.fact_type_id,
266
+ f.hash,
267
+ ('{"fields":' || (('{"a":' || f.fields::text || '}')::json ->> 'a') ||
268
+ ',"predecessors":' || (('{"a":' || f.predecessors::text || '}')::json ->> 'a') || '}')::jsonb,
269
+ f.date_learned
270
+ FROM legacy.fact f
271
+ JOIN public.fact_type t
272
+ ON t.name = f.type
273
+ ON CONFLICT DO NOTHING;
274
+
275
+ INSERT INTO public.edge
276
+ (role_id, successor_fact_id, predecessor_fact_id)
277
+ SELECT r.role_id, s.fact_id, p.fact_id
278
+ FROM legacy.edge e
279
+ JOIN public.fact_type st
280
+ ON st.name = e.successor_type
281
+ JOIN public.fact s
282
+ ON s.fact_type_id = st.fact_type_id
283
+ AND s.hash = e.successor_hash
284
+ JOIN public.fact_type pt
285
+ ON pt.name = e.predecessor_type
286
+ JOIN public.fact p
287
+ ON p.fact_type_id = pt.fact_type_id
288
+ AND p.hash = e.predecessor_hash
289
+ JOIN public.role r
290
+ ON r.defining_fact_type_id = st.fact_type_id
291
+ AND r.name = e.role
292
+ ON CONFLICT DO NOTHING;
293
+
294
+ INSERT INTO public.ancestor
295
+ (fact_id, ancestor_fact_id)
296
+ WITH RECURSIVE a(fact_id, ancestor_fact_id) AS (
297
+ SELECT e.successor_fact_id, e.predecessor_fact_id
298
+ FROM public.edge e
299
+ UNION ALL
300
+ SELECT e.successor_fact_id, a.ancestor_fact_id
301
+ FROM public.edge e
302
+ JOIN a ON a.fact_id = e.predecessor_fact_id
303
+ )
304
+ SELECT DISTINCT a.fact_id, a.ancestor_fact_id
305
+ FROM a
306
+ ON CONFLICT DO NOTHING;
307
+
308
+ INSERT INTO public.public_key
309
+ (public_key)
310
+ SELECT DISTINCT public_key
311
+ FROM legacy.signature
312
+ ON CONFLICT DO NOTHING;
313
+
314
+ INSERT INTO public.signature
315
+ (fact_id, public_key_id, signature, date_learned)
316
+ SELECT f.fact_id, pk.public_key_id, s.signature, s.date_learned
317
+ FROM legacy.signature s
318
+ JOIN public.fact_type t
319
+ ON t.name = s.type
320
+ JOIN public.fact f
321
+ ON f.fact_type_id = t.fact_type_id AND f.hash = s.hash
322
+ JOIN public.public_key pk
323
+ ON pk.public_key = s.public_key
324
+ ON CONFLICT DO NOTHING;
325
+
326
+ END IF;
327
+
328
+ END
329
+ $do$
@@ -0,0 +1,68 @@
1
+ import {
2
+ Channel,
3
+ FactEnvelope,
4
+ FactRecord,
5
+ FactReference,
6
+ Fork,
7
+ LoginResponse,
8
+ Observable,
9
+ Query,
10
+ Specification,
11
+ UserIdentity,
12
+ } from "jinaga";
13
+
14
+ import { Keystore } from "../keystore";
15
+ import { Authentication } from "./authentication";
16
+
17
+ export class AuthenticationDevice implements Authentication {
18
+ constructor(
19
+ private inner: Fork,
20
+ private keystore: Keystore,
21
+ private localDeviceIdentity: UserIdentity
22
+ ) {}
23
+
24
+ async close(): Promise<void> {
25
+ await this.inner.close();
26
+ await this.keystore.close();
27
+ }
28
+
29
+ async login(): Promise<LoginResponse> {
30
+ throw new Error('No logged in user.');
31
+ }
32
+
33
+ async local(): Promise<FactRecord> {
34
+ return await this.keystore.getOrCreateDeviceFact(this.localDeviceIdentity);
35
+ }
36
+
37
+ from(fact: FactReference, query: Query): Observable {
38
+ return this.inner.from(fact, query);
39
+ }
40
+
41
+ save(envelopes: FactEnvelope[]): Promise<FactEnvelope[]> {
42
+ return this.inner.save(envelopes);
43
+ }
44
+
45
+ query(start: FactReference, query: Query): Promise<FactReference[][]> {
46
+ return this.inner.query(start, query);
47
+ }
48
+
49
+ read(start: FactReference[], specification: Specification): Promise<any[]> {
50
+ return this.inner.read(start, specification);
51
+ }
52
+
53
+ whichExist(references: FactReference[]): Promise<FactReference[]> {
54
+ throw new Error("whichExist method not implemented on AuthenticationDevice.");
55
+ }
56
+
57
+ load(references: FactReference[]): Promise<FactRecord[]> {
58
+ return this.inner.load(references);
59
+ }
60
+
61
+ addChannel(fact: FactReference, query: Query): Channel {
62
+ return this.inner.addChannel(fact, query);
63
+ }
64
+
65
+ removeChannel(channel: Channel): void {
66
+ return this.inner.removeChannel(channel);
67
+ }
68
+ }
@@ -0,0 +1,59 @@
1
+ import { Channel, FactEnvelope, FactRecord, FactReference, Fork, Observable, Query, Specification, WebClient } from "jinaga";
2
+
3
+ import { Authentication } from "./authentication";
4
+
5
+ export class Principal {
6
+
7
+ }
8
+
9
+ export class AuthenticationImpl implements Authentication {
10
+ private principal: Principal;
11
+
12
+ constructor(private inner: Fork, private client: WebClient) {
13
+ }
14
+
15
+ async close(): Promise<void> {
16
+ await this.inner.close();
17
+ }
18
+
19
+ login() {
20
+ return this.client.login();
21
+ }
22
+
23
+ local(): Promise<FactRecord> {
24
+ throw new Error('Local device has no persistence.');
25
+ }
26
+
27
+ async save(envelopes: FactEnvelope[]): Promise<FactEnvelope[]> {
28
+ const saved = await this.inner.save(envelopes);
29
+ return saved;
30
+ }
31
+
32
+ query(start: FactReference, query: Query) {
33
+ return this.inner.query(start, query);
34
+ }
35
+
36
+ read(start: FactReference[], specification: Specification): Promise<any[]> {
37
+ return this.inner.read(start, specification);
38
+ }
39
+
40
+ whichExist(references: FactReference[]): Promise<FactReference[]> {
41
+ throw new Error("whichExist method not implemented on AuthenticationImpl.");
42
+ }
43
+
44
+ load(references: FactReference[]): Promise<FactRecord[]> {
45
+ return this.inner.load(references);
46
+ }
47
+
48
+ from(fact: FactReference, query: Query): Observable {
49
+ return this.inner.from(fact, query);
50
+ }
51
+
52
+ addChannel(fact: FactReference, query: Query): Channel {
53
+ return this.inner.addChannel(fact, query);
54
+ }
55
+
56
+ removeChannel(channel: Channel) {
57
+ this.inner.removeChannel(channel);
58
+ }
59
+ }
@@ -0,0 +1,95 @@
1
+ import {
2
+ AuthorizationEngine,
3
+ AuthorizationRules,
4
+ Channel,
5
+ FactEnvelope,
6
+ FactRecord,
7
+ FactReference,
8
+ Feed,
9
+ LoginResponse,
10
+ Observable,
11
+ Query,
12
+ Specification,
13
+ UserIdentity,
14
+ } from "jinaga";
15
+
16
+ import { Keystore } from "../keystore";
17
+ import { Authentication } from "./authentication";
18
+
19
+ export class AuthenticationSession implements Authentication {
20
+ private authorizationEngine: AuthorizationEngine | null;
21
+
22
+ constructor(
23
+ private inner: Feed,
24
+ private keystore: Keystore,
25
+ authorizationRules: AuthorizationRules | null,
26
+ private userIdentity: UserIdentity,
27
+ private displayName: string,
28
+ private localDeviceIdentity: UserIdentity
29
+ ) {
30
+ this.authorizationEngine = authorizationRules &&
31
+ new AuthorizationEngine(authorizationRules, inner);
32
+ }
33
+
34
+ async close(): Promise<void> {
35
+ await this.inner.close();
36
+ await this.keystore.close();
37
+ }
38
+
39
+ async login(): Promise<LoginResponse> {
40
+ const userFact = await this.keystore.getOrCreateUserFact(this.userIdentity);
41
+ const signedFacts = await this.keystore.signFacts(this.userIdentity, [userFact]);
42
+ await this.inner.save(signedFacts);
43
+ return {
44
+ userFact,
45
+ profile: {
46
+ displayName: this.displayName
47
+ }
48
+ };
49
+ }
50
+
51
+ async local(): Promise<FactRecord> {
52
+ const deviceFact = await this.keystore.getOrCreateDeviceFact(this.localDeviceIdentity);
53
+ const signedFact: FactEnvelope = {
54
+ fact: deviceFact,
55
+ signatures: []
56
+ };
57
+ await this.inner.save([signedFact]);
58
+ return deviceFact;
59
+ }
60
+
61
+ from(fact: FactReference, query: Query): Observable {
62
+ return this.inner.from(fact, query);
63
+ }
64
+
65
+ async save(envelopes: FactEnvelope[]): Promise<FactEnvelope[]> {
66
+ const userFact = await this.keystore.getUserFact(this.userIdentity);
67
+ const facts = envelopes.map(envelope => envelope.fact);
68
+ const authorizedFacts = await this.authorizationEngine.authorizeFacts(facts, userFact);
69
+ const signedFacts = await this.keystore.signFacts(this.userIdentity, authorizedFacts);
70
+ return await this.inner.save(signedFacts);
71
+ }
72
+
73
+ query(start: FactReference, query: Query): Promise<FactReference[][]> {
74
+ return this.inner.query(start, query);
75
+ }
76
+
77
+ read(start: FactReference[], specification: Specification): Promise<any[]> {
78
+ return this.inner.read(start, specification);
79
+ }
80
+
81
+ whichExist(references: FactReference[]): Promise<FactReference[]> {
82
+ throw new Error("WhichExist method not implemented on AuthenticationSession.");
83
+ }
84
+
85
+ load(references: FactReference[]): Promise<FactRecord[]> {
86
+ return this.inner.load(references);
87
+ }
88
+
89
+ addChannel(fact: FactReference, query: Query): Channel {
90
+ return null;
91
+ }
92
+
93
+ removeChannel(channel: Channel): void {
94
+ }
95
+ }
@@ -0,0 +1,6 @@
1
+ import { FactRecord, Fork, LoginResponse } from "jinaga";
2
+
3
+ export interface Authentication extends Fork {
4
+ login(): Promise<LoginResponse>;
5
+ local(): Promise<FactRecord>;
6
+ }
@@ -0,0 +1,45 @@
1
+ import { FactEnvelope, FactRecord, FactReference, Feed, Observable, Query, Specification, WebClient } from "jinaga";
2
+
3
+ export class Principal {
4
+
5
+ }
6
+
7
+ export class Authentication implements Feed {
8
+ private principal: Principal;
9
+
10
+ constructor(private inner: Feed, private client: WebClient) {
11
+ }
12
+
13
+ async close(): Promise<void> {
14
+ await this.inner.close();
15
+ }
16
+
17
+ login() {
18
+ return this.client.login();
19
+ }
20
+
21
+ async save(envelopes: FactEnvelope[]): Promise<FactEnvelope[]> {
22
+ const saved = await this.inner.save(envelopes);
23
+ return saved;
24
+ }
25
+
26
+ query(start: FactReference, query: Query) {
27
+ return this.inner.query(start, query);
28
+ }
29
+
30
+ read(start: FactReference[], specification: Specification): Promise<any[]> {
31
+ return this.inner.read(start, specification);
32
+ }
33
+
34
+ whichExist(references: FactReference[]): Promise<FactReference[]> {
35
+ throw new Error("whichExist method not implemented on Authentication.");
36
+ }
37
+
38
+ load(references: FactReference[]): Promise<FactRecord[]> {
39
+ return this.inner.load(references);
40
+ }
41
+
42
+ from(fact: FactReference, query: Query): Observable {
43
+ return this.inner.from(fact, query);
44
+ }
45
+ }
@@ -0,0 +1,67 @@
1
+ import {
2
+ Authorization,
3
+ AuthorizationEngine,
4
+ AuthorizationRules,
5
+ FactEnvelope,
6
+ FactRecord,
7
+ FactReference,
8
+ Feed,
9
+ Query,
10
+ Specification,
11
+ UserIdentity,
12
+ } from "jinaga";
13
+
14
+ import { Keystore } from "../keystore";
15
+
16
+ export class AuthorizationKeystore implements Authorization {
17
+ private authorizationEngine: AuthorizationEngine | null;
18
+
19
+ constructor(
20
+ private feed: Feed,
21
+ private keystore: Keystore,
22
+ authorizationRules: AuthorizationRules | null) {
23
+
24
+ this.authorizationEngine = authorizationRules &&
25
+ new AuthorizationEngine(authorizationRules, feed);
26
+ }
27
+
28
+ async getOrCreateUserFact(userIdentity: UserIdentity) {
29
+ const userFact = await this.keystore.getOrCreateUserFact(userIdentity);
30
+ const envelopes = [
31
+ <FactEnvelope>{
32
+ fact: userFact,
33
+ signatures: []
34
+ }
35
+ ];
36
+ await this.feed.save(envelopes);
37
+ return userFact;
38
+ }
39
+
40
+ query(userIdentity: UserIdentity, start: FactReference, query: Query) {
41
+ return this.feed.query(start, query);
42
+ }
43
+
44
+ read(userIdentity: UserIdentity, start: FactReference[], specification: Specification) {
45
+ return this.feed.read(start, specification);
46
+ }
47
+
48
+ load(userIdentity: UserIdentity, references: FactReference[]) {
49
+ return this.feed.load(references);
50
+ }
51
+
52
+ async save(userIdentity: UserIdentity, facts: FactRecord[]) {
53
+ if (!this.authorizationEngine) {
54
+ const envelopes = await this.feed.save(facts.map(fact => ({
55
+ fact,
56
+ signatures: []
57
+ })));
58
+ return envelopes.map(envelope => envelope.fact);
59
+ }
60
+
61
+ const userFact = await this.keystore.getUserFact(userIdentity);
62
+ const authorizedFacts = await this.authorizationEngine.authorizeFacts(facts, userFact);
63
+ const signedFacts = await this.keystore.signFacts(userIdentity, authorizedFacts);
64
+ const envelopes = await this.feed.save(signedFacts);
65
+ return envelopes.map(envelope => envelope.fact);
66
+ }
67
+ }