jinaga-server 2.6.2 → 3.0.1

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 (36) hide show
  1. package/dist/authentication/authentication-device.js +27 -6
  2. package/dist/authentication/authentication-device.js.map +1 -1
  3. package/dist/authentication/authentication-session.js +27 -6
  4. package/dist/authentication/authentication-session.js.map +1 -1
  5. package/dist/authorization/authorization-keystore.d.ts +4 -5
  6. package/dist/authorization/authorization-keystore.js +42 -18
  7. package/dist/authorization/authorization-keystore.js.map +1 -1
  8. package/dist/http/router.d.ts +1 -2
  9. package/dist/http/router.js +15 -18
  10. package/dist/http/router.js.map +1 -1
  11. package/dist/jinaga-server.js +5 -6
  12. package/dist/jinaga-server.js.map +1 -1
  13. package/dist/postgres/postgres-store.d.ts +2 -5
  14. package/dist/postgres/postgres-store.js +44 -121
  15. package/dist/postgres/postgres-store.js.map +1 -1
  16. package/dist/postgres/query-description.js +5 -1
  17. package/dist/postgres/query-description.js.map +1 -1
  18. package/integration-test/jinaga-test/jinaga.test.js +247 -231
  19. package/integration-test/jinaga-test/package-lock.json +9 -52
  20. package/integration-test/jinaga-test/package.json +2 -5
  21. package/package.json +2 -3
  22. package/replicator/index.ts +1 -1
  23. package/replicator/tsconfig.json +1 -0
  24. package/src/authentication/authentication-device.ts +29 -7
  25. package/src/authentication/authentication-session.ts +29 -7
  26. package/src/authorization/authorization-keystore.ts +42 -22
  27. package/src/http/router.ts +14 -24
  28. package/src/jinaga-server.ts +5 -6
  29. package/src/postgres/postgres-store.ts +63 -149
  30. package/src/postgres/query-description.ts +6 -2
  31. package/test/authorization/authorizationSpec.ts +75 -89
  32. package/dist/postgres/sql.d.ts +0 -10
  33. package/dist/postgres/sql.js +0 -408
  34. package/dist/postgres/sql.js.map +0 -1
  35. package/src/postgres/sql.ts +0 -498
  36. package/test/postgres/postgresSpec.ts +0 -391
@@ -1,5 +1,5 @@
1
1
  import { FactReference, Label, Match, PathCondition } from "jinaga";
2
- import { FactTypeMap, RoleMap, ensureGetFactTypeId, getFactTypeId, getRoleId } from "./maps";
2
+ import { FactTypeMap, RoleMap, getFactTypeId, getRoleId } from "./maps";
3
3
 
4
4
  export interface FactDescription {
5
5
  type: string;
@@ -323,9 +323,13 @@ export class QueryDescriptionBuider {
323
323
  if (givenIndex < 0) {
324
324
  throw new Error(`No input parameter found for label ${condition.labelRight}`);
325
325
  }
326
+ const factTypeId = getFactTypeId(this.factTypes, start[givenIndex].type);
327
+ if (!factTypeId) {
328
+ return { queryDescription: QueryDescription.unsatisfiable, knownFacts };
329
+ }
326
330
  const { queryDescription: newQueryDescription, factDescription } = queryDescription.withInputParameter(
327
331
  given[givenIndex],
328
- ensureGetFactTypeId(this.factTypes, start[givenIndex].type),
332
+ factTypeId,
329
333
  start[givenIndex].hash,
330
334
  path
331
335
  );
@@ -1,21 +1,59 @@
1
1
  import {
2
- AuthenticationNoOp,
3
2
  AuthorizationRules,
3
+ buildModel,
4
4
  dehydrateFact,
5
- ensure,
5
+ FactEnvelope,
6
6
  FactManager,
7
7
  FactRecord,
8
8
  hydrate,
9
- Jinaga as j,
10
9
  MemoryStore,
11
10
  NetworkNoOp,
12
11
  ObservableSource,
13
- PassThroughFork
12
+ PassThroughFork,
13
+ User
14
14
  } from "jinaga";
15
15
 
16
16
  import { AuthorizationKeystore } from "../../src/authorization/authorization-keystore";
17
17
  import { MemoryKeystore } from "../../src/memory/memory-keystore";
18
18
 
19
+ class Hashtag {
20
+ public static Type = "Hashtag" as const;
21
+ public type = Hashtag.Type;
22
+
23
+ constructor(
24
+ public word: string
25
+ ) { }
26
+ }
27
+
28
+ class Tweet {
29
+ public static Type = "Tweet" as const;
30
+ public type = Tweet.Type;
31
+
32
+ constructor(
33
+ public message: string,
34
+ public sender: User
35
+ ) { }
36
+ }
37
+
38
+ class Like {
39
+ public static Type = "Like" as const;
40
+ public type = Like.Type;
41
+
42
+ constructor(
43
+ public user: User,
44
+ public tweet: Tweet
45
+ ) { }
46
+ }
47
+
48
+ class Delete {
49
+ public static Type = "Delete" as const;
50
+ public type = Delete.Type;
51
+
52
+ constructor(
53
+ public tweet: Tweet
54
+ ) { }
55
+ }
56
+
19
57
  describe('Authorization', () => {
20
58
  it('should authorize empty save', async () => {
21
59
  const authorization = givenAuthorization();
@@ -25,19 +63,13 @@ describe('Authorization', () => {
25
63
 
26
64
  it('should save a new fact', async () => {
27
65
  const authorization = givenAuthorization();
28
- const result = await whenSave(authorization, dehydrateFact({
29
- type: 'Hashtag',
30
- word: 'vorpal'
31
- }));
66
+ const result = await whenSave(authorization, dehydrateFact(new Hashtag('vorpal')));
32
67
  expect(result.length).toEqual(1);
33
68
  });
34
69
 
35
70
  it('should save a fact once', async () => {
36
71
  const authorization = givenAuthorization();
37
- const facts = dehydrateFact({
38
- type: 'Hashtag',
39
- word: 'vorpal'
40
- });
72
+ const facts = dehydrateFact(new Hashtag('vorpal'));
41
73
  await whenSave(authorization, facts);
42
74
  const result = await whenSave(authorization, facts);
43
75
  expect(result.length).toEqual(0);
@@ -46,64 +78,36 @@ describe('Authorization', () => {
46
78
  it('should reject a fact from an unauthorized user', async () => {
47
79
  const authorization = givenAuthorization();
48
80
  const mickeyMouse = givenOtherUser();
49
- const promise = whenSave(authorization, dehydrateFact({
50
- type: 'Tweet',
51
- message: 'Twas brillig',
52
- sender: mickeyMouse
53
- }));
81
+ const promise = whenSave(authorization, dehydrateFact(new Tweet("Twas brillig", mickeyMouse)));
54
82
  await expect(promise).rejects.not.toBeNull();
55
83
  });
56
84
 
57
85
  it('should accept a fact from an authorized user', async () => {
58
86
  const authorization = givenAuthorization();
59
87
  const lewiscarrol = await givenLoggedInUser(authorization);
60
- const result = await whenSave(authorization, dehydrateFact({
61
- type: 'Tweet',
62
- message: 'Twas brillig',
63
- sender: lewiscarrol
64
- }));
88
+ const result = await whenSave(authorization, dehydrateFact(new Tweet("Twas brillig", lewiscarrol)));
65
89
  expect(result.length).toBeGreaterThan(0);
66
90
  });
67
91
 
68
92
  it('should accept a predecessor from an authorized user', async () => {
69
93
  const authorization = givenAuthorization();
70
94
  const lewiscarrol = await givenLoggedInUser(authorization);
71
- const result = await whenSave(authorization, dehydrateFact({
72
- type: 'Like',
73
- user: lewiscarrol,
74
- tweet: {
75
- type: 'Tweet',
76
- message: 'Twas Brillig',
77
- sender: lewiscarrol
78
- }
79
- }));
80
- expect(result.filter(r => r.type === 'Tweet').length).toEqual(1);
95
+ const result = await whenSave(authorization, dehydrateFact(new Like(lewiscarrol, new Tweet('Twas Brillig', lewiscarrol))));
96
+ expect(result.filter(r => r.fact.type === 'Tweet').length).toEqual(1);
81
97
  });
82
98
 
83
99
  it('should reject a predecessor from an unauthorized user', async () => {
84
100
  const authorization = givenAuthorization();
85
101
  const lewiscarrol = await givenLoggedInUser(authorization);
86
102
  const mickeyMouse = givenOtherUser();
87
- const promise = whenSave(authorization, dehydrateFact({
88
- type: 'Like',
89
- user: lewiscarrol,
90
- tweet: {
91
- type: 'Tweet',
92
- message: 'Hiya, Pal!',
93
- sender: mickeyMouse
94
- }
95
- }));
103
+ const promise = whenSave(authorization, dehydrateFact(new Like(lewiscarrol, new Tweet("Hiya, Pal!", mickeyMouse))));
96
104
  await expect(promise).rejects.not.toBeNull();
97
105
  });
98
106
 
99
107
  it('should accept a pre-existing predecessor from an unauthorized user', async () => {
100
108
  const storage = givenStorage();
101
109
  const mickeyMouse = givenOtherUser();
102
- const tweet = {
103
- type: 'Tweet',
104
- message: 'Hiya, Pal!',
105
- sender: mickeyMouse
106
- };
110
+ const tweet = new Tweet("Hiya, Pal!", mickeyMouse);
107
111
  await storage.save(dehydrateFact(tweet).map(f => ({ fact: f, signatures: [] })));
108
112
 
109
113
  const authorization = givenAuthorizationWithStorage(storage);
@@ -114,17 +118,13 @@ describe('Authorization', () => {
114
118
  tweet: tweet
115
119
  }));
116
120
  expect(result.length).toBeGreaterThan(0);
117
- expect(result.filter(r => r.type === 'Tweet').length).toEqual(0);
121
+ expect(result.filter(r => r.fact.type === 'Tweet').length).toEqual(0);
118
122
  });
119
123
 
120
124
  it('should accept a fact authorized by predecessor', async () => {
121
125
  const authorization = givenAuthorization();
122
126
  const lewiscarrol = await givenLoggedInUser(authorization);
123
- const tweet = {
124
- type: 'Tweet',
125
- message: 'Twas brillig',
126
- sender: lewiscarrol
127
- };
127
+ const tweet = new Tweet("Twas brillig", lewiscarrol);
128
128
  await whenSave(authorization, dehydrateFact(tweet));
129
129
 
130
130
  const result = await whenSave(authorization, dehydrateFact({
@@ -137,11 +137,7 @@ describe('Authorization', () => {
137
137
  it('should accept a fact based on in-flight predecessor', async () => {
138
138
  const authorization = givenAuthorization();
139
139
  const lewiscarrol = await givenLoggedInUser(authorization);
140
- const tweet = {
141
- type: 'Tweet',
142
- message: 'Twas brillig',
143
- sender: lewiscarrol
144
- };
140
+ const tweet = new Tweet("Twas brillig", lewiscarrol);
145
141
  // Note that this is missing.
146
142
  // await whenSave(authorization, dehydrateFact(tweet));
147
143
 
@@ -165,32 +161,39 @@ function givenStorage() {
165
161
  function givenAuthorizationWithStorage(storage: MemoryStore) {
166
162
  const keystore = new MemoryKeystore();
167
163
  keystore.getOrCreateUserFact(givenMockUserIdentity());
168
- const authentication = new AuthenticationNoOp();
169
164
  const fork = new PassThroughFork(storage);
170
165
  const observableSource = new ObservableSource(storage);
171
166
  const network = new NetworkNoOp();
172
- const factManager = new FactManager(authentication, fork, observableSource, storage, network);
173
- const authorizationRules = new AuthorizationRules(undefined)
174
- .any('Hashtag')
175
- .no('Jinaga.User')
176
- .type('Tweet', j.for(tweetSender))
177
- .type('Like', j.for(likeUser))
178
- .type('Delete', j.for(deleteSender))
167
+ const factManager = new FactManager(fork, observableSource, storage, network);
168
+ const model = buildModel(b => b
169
+ .type(Hashtag)
170
+ .type(User)
171
+ .type(Tweet, m => m
172
+ .predecessor("sender", User))
173
+ .type(Like, m => m
174
+ .predecessor("user", User)
175
+ .predecessor("tweet", Tweet))
176
+ .type(Delete, m => m
177
+ .predecessor("tweet", Tweet))
178
+ );
179
+ const authorizationRules = new AuthorizationRules(model)
180
+ .any(Hashtag)
181
+ .no(User)
182
+ .type(Tweet, t => t.sender)
183
+ .type(Like, l => l.user)
184
+ .type(Delete, d => d.tweet.sender)
179
185
  ;
180
186
  return new AuthorizationKeystore(factManager, storage, keystore, authorizationRules, null);
181
187
  }
182
188
 
183
189
  function givenOtherUser() {
184
- return {
185
- type: 'Jinaga.User',
186
- publicKey: 'other'
187
- };
190
+ return new User('other');
188
191
  }
189
192
 
190
193
  async function givenLoggedInUser(authorization: AuthorizationKeystore) {
191
194
  const userIdentity = givenMockUserIdentity();
192
195
  const userFact = await authorization.getOrCreateUserFact(userIdentity);
193
- const user = hydrate<{}>(userFact);
196
+ const user = hydrate<User>(userFact);
194
197
  return user;
195
198
  }
196
199
 
@@ -203,24 +206,7 @@ function givenMockUserIdentity() {
203
206
 
204
207
  async function whenSave(authorization: AuthorizationKeystore, facts: FactRecord[]) {
205
208
  const userIdentity = givenMockUserIdentity();
206
- const result = await authorization.save(userIdentity, facts);
209
+ const envelopes: FactEnvelope[] = facts.map(f => ({ fact: f, signatures: [] }));
210
+ const result = await authorization.save(userIdentity, envelopes);
207
211
  return result;
208
- }
209
-
210
- function tweetSender(t: { sender: {} }) {
211
- ensure(t).has("sender", "Jinaga.User");
212
-
213
- return j.match(t.sender);
214
- }
215
-
216
- function likeUser(l: { user: {} }) {
217
- ensure(l).has("user", "Jinaga.User");
218
-
219
- return j.match(l.user);
220
- }
221
-
222
- function deleteSender(d: { tweet: { sender: {} } }) {
223
- ensure(d).has("tweet", "Tweet").has("sender", "Jinaga.User");
224
-
225
- return j.match(d.tweet.sender);
226
212
  }
@@ -1,10 +0,0 @@
1
- import { FactReference, Step } from "jinaga";
2
- import { FactTypeMap, RoleMap } from "./maps";
3
- export declare type SqlQuery = {
4
- empty: boolean;
5
- sql: string;
6
- parameters: any[];
7
- pathLength: number;
8
- factTypeNames: string[];
9
- };
10
- export declare function sqlFromSteps(start: FactReference, steps: Step[], factTypes: FactTypeMap, roleMap: RoleMap, schema: string): SqlQuery | null;