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.
- package/LICENSE +22 -0
- package/dist/authentication/authentication-device.d.ts +20 -0
- package/dist/authentication/authentication-device.js +61 -0
- package/dist/authentication/authentication-device.js.map +1 -0
- package/dist/authentication/authentication-impl.d.ts +21 -0
- package/dist/authentication/authentication-impl.js +61 -0
- package/dist/authentication/authentication-impl.js.map +1 -0
- package/dist/authentication/authentication-session.d.ts +23 -0
- package/dist/authentication/authentication-session.js +85 -0
- package/dist/authentication/authentication-session.js.map +1 -0
- package/dist/authentication/authentication.d.ts +5 -0
- package/dist/authentication/authentication.js +3 -0
- package/dist/authentication/authentication.js.map +1 -0
- package/dist/authentication.d.ts +17 -0
- package/dist/authentication.js +52 -0
- package/dist/authentication.js.map +1 -0
- package/dist/authorization/authorization-keystore.d.ts +13 -0
- package/dist/authorization/authorization-keystore.js +61 -0
- package/dist/authorization/authorization-keystore.js.map +1 -0
- package/dist/http/node-http.d.ts +7 -0
- package/dist/http/node-http.js +126 -0
- package/dist/http/node-http.js.map +1 -0
- package/dist/http/router.d.ts +20 -0
- package/dist/http/router.js +223 -0
- package/dist/http/router.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/jinaga-server.d.ts +18 -0
- package/dist/jinaga-server.js +101 -0
- package/dist/jinaga-server.js.map +1 -0
- package/dist/keystore.d.ts +9 -0
- package/dist/keystore.js +3 -0
- package/dist/keystore.js.map +1 -0
- package/dist/memory/memory-keystore.d.ts +16 -0
- package/dist/memory/memory-keystore.js +86 -0
- package/dist/memory/memory-keystore.js.map +1 -0
- package/dist/postgres/connection.d.ts +12 -0
- package/dist/postgres/connection.js +83 -0
- package/dist/postgres/connection.js.map +1 -0
- package/dist/postgres/edge-record.d.ts +9 -0
- package/dist/postgres/edge-record.js +30 -0
- package/dist/postgres/edge-record.js.map +1 -0
- package/dist/postgres/maps.d.ts +21 -0
- package/dist/postgres/maps.js +86 -0
- package/dist/postgres/maps.js.map +1 -0
- package/dist/postgres/postgres-keystore.d.ts +20 -0
- package/dist/postgres/postgres-keystore.js +168 -0
- package/dist/postgres/postgres-keystore.js.map +1 -0
- package/dist/postgres/postgres-store.d.ts +20 -0
- package/dist/postgres/postgres-store.js +717 -0
- package/dist/postgres/postgres-store.js.map +1 -0
- package/dist/postgres/query-description-builder.d.ts +13 -0
- package/dist/postgres/query-description-builder.js +104 -0
- package/dist/postgres/query-description-builder.js.map +1 -0
- package/dist/postgres/query-description.d.ts +71 -0
- package/dist/postgres/query-description.js +256 -0
- package/dist/postgres/query-description.js.map +1 -0
- package/dist/postgres/specification-result-sql.d.ts +41 -0
- package/dist/postgres/specification-result-sql.js +260 -0
- package/dist/postgres/specification-result-sql.js.map +1 -0
- package/dist/postgres/specification-sql.d.ts +3 -0
- package/dist/postgres/specification-sql.js +119 -0
- package/dist/postgres/specification-sql.js.map +1 -0
- package/dist/postgres/sql.d.ts +10 -0
- package/dist/postgres/sql.js +396 -0
- package/dist/postgres/sql.js.map +1 -0
- package/dist/util/fn.d.ts +6 -0
- package/dist/util/fn.js +81 -0
- package/dist/util/fn.js.map +1 -0
- package/dist/util/promise.d.ts +1 -0
- package/dist/util/promise.js +10 -0
- package/dist/util/promise.js.map +1 -0
- package/docs/registrations.sql +22 -0
- package/docs/specification.txt +41 -0
- package/docs/sql-generator.gv +25 -0
- package/integration-test/docker-compose.yaml +13 -0
- package/integration-test/jinaga-test/Dockerfile +12 -0
- package/integration-test/jinaga-test/jinaga.test.js +425 -0
- package/integration-test/jinaga-test/package-lock.json +6767 -0
- package/integration-test/jinaga-test/package.json +25 -0
- package/integration-test/postgres/0-init-app-db.sh +16 -0
- package/integration-test/postgres/1-setup.sql +219 -0
- package/integration-test/postgres/2-grant.sh +17 -0
- package/integration-test/postgres/Dockerfile +5 -0
- package/integration-test/run.sh +17 -0
- package/integration-test/start_db.sh +2 -0
- package/integration-test/stop_db.sh +3 -0
- package/integration-test/test.sh +8 -0
- package/interactive/index.js +56 -0
- package/jest.config.js +12 -0
- package/package.json +51 -0
- package/scripts/combined.sql +46 -0
- package/scripts/cte.sql +55 -0
- package/scripts/separate.sql +27 -0
- package/setup.sh +34 -0
- package/setup.sql +329 -0
- package/src/authentication/authentication-device.ts +68 -0
- package/src/authentication/authentication-impl.ts +59 -0
- package/src/authentication/authentication-session.ts +95 -0
- package/src/authentication/authentication.ts +6 -0
- package/src/authentication.ts +45 -0
- package/src/authorization/authorization-keystore.ts +67 -0
- package/src/http/node-http.ts +106 -0
- package/src/http/router.ts +237 -0
- package/src/index.ts +1 -0
- package/src/jinaga-server.ts +125 -0
- package/src/keystore.ts +10 -0
- package/src/memory/memory-keystore.ts +93 -0
- package/src/postgres/connection.ts +73 -0
- package/src/postgres/edge-record.ts +36 -0
- package/src/postgres/maps.ts +89 -0
- package/src/postgres/postgres-keystore.ts +167 -0
- package/src/postgres/postgres-store.ts +874 -0
- package/src/postgres/query-description-builder.ts +116 -0
- package/src/postgres/query-description.ts +385 -0
- package/src/postgres/specification-result-sql.ts +362 -0
- package/src/postgres/specification-sql.ts +138 -0
- package/src/postgres/sql.ts +482 -0
- package/src/util/fn.ts +63 -0
- package/src/util/promise.ts +5 -0
- package/test/authorization/authorizationSpec.ts +209 -0
- package/test/postgres/postgresSpec.ts +385 -0
- package/test/postgres/postgresSpecificationSpec.ts +742 -0
- package/test/reporter.js +25 -0
- package/tsconfig.json +25 -0
- 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,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
|
+
}
|