@nymphjs/tilmeld 1.0.0-alpha.2 → 1.0.0-alpha.6

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/src/Tilmeld.ts CHANGED
@@ -4,6 +4,7 @@ import {
4
4
  FormattedSelector,
5
5
  Options,
6
6
  TilmeldInterface,
7
+ TilmeldAccessLevels,
7
8
  } from '@nymphjs/nymph';
8
9
  import { Request, Response } from 'express';
9
10
 
@@ -23,15 +24,10 @@ import { AccessControlData } from './Tilmeld.types';
23
24
  * @see http://nymph.io/
24
25
  */
25
26
  export default class Tilmeld implements TilmeldInterface {
26
- public static NO_ACCESS = 0;
27
- public static READ_ACCESS = 1;
28
- public static WRITE_ACCESS = 2;
29
- public static FULL_ACCESS = 4;
30
-
31
27
  /**
32
28
  * The Nymph instance.
33
29
  */
34
- public nymph: Nymph;
30
+ public nymph: Nymph = {} as Nymph;
35
31
 
36
32
  /**
37
33
  * The Tilmeld config.
@@ -70,30 +66,32 @@ export default class Tilmeld implements TilmeldInterface {
70
66
  public request: Request | null = null;
71
67
  public response: Response | null = null;
72
68
 
69
+ /**
70
+ * Skip the authenticate step of initialization.
71
+ */
72
+ private skipAuthenticate = false;
73
+
73
74
  /**
74
75
  * Create a new instance of Tilmeld.
75
76
  *
76
77
  * @param config The Tilmeld configuration.
77
78
  */
78
79
  public constructor(config: Partial<Config> & { jwtSecret: string }) {
79
- this.nymph = new Nymph();
80
80
  this.config = { ...defaults, ...config };
81
81
  }
82
82
 
83
83
  /**
84
- * Check to see if the current user has an ability.
85
- *
86
- * If `ability` is undefined, it will check to see if a user is currently
87
- * logged in.
88
- *
89
- * @param ability The ability.
90
- * @returns Whether the user has the given ability.
84
+ * This is used internally by Nymph. Don't call it yourself.
85
+ * @returns A clone of this instance.
91
86
  */
92
- public gatekeeper(ability?: string): boolean {
93
- if (this.currentUser == null) {
94
- return false;
95
- }
96
- return this.currentUser.$gatekeeper(ability);
87
+ public clone() {
88
+ const tilmeld = new Tilmeld(this.config);
89
+ tilmeld.request = this.request;
90
+ tilmeld.response = this.response;
91
+ tilmeld.currentUser = this.currentUser;
92
+ tilmeld.skipAuthenticate = true;
93
+
94
+ return tilmeld;
97
95
  }
98
96
 
99
97
  /**
@@ -115,28 +113,47 @@ export default class Tilmeld implements TilmeldInterface {
115
113
  class NymphUser extends User {}
116
114
  NymphUser.nymph = this.nymph;
117
115
  NymphUser.tilmeld = this;
116
+ (NymphUser as any).skipOnClone = true;
118
117
  this.User = NymphUser;
119
- this.nymph.setEntityClass(NymphUser.class, NymphUser);
118
+ this.nymph.addEntityClass(NymphUser);
120
119
  class NymphGroup extends Group {}
121
120
  NymphGroup.nymph = this.nymph;
122
121
  NymphGroup.tilmeld = this;
122
+ (NymphUser as any).skipOnClone = true;
123
123
  this.Group = NymphGroup;
124
- this.nymph.setEntityClass(NymphGroup.class, NymphGroup);
124
+ this.nymph.addEntityClass(NymphGroup);
125
125
 
126
126
  this.initAccessControl();
127
- if (this.request != null) {
127
+ if (this.request != null && !this.skipAuthenticate) {
128
128
  this.authenticate();
129
129
  }
130
+ this.skipAuthenticate = false;
130
131
  }
131
132
 
132
- private initAccessControl() {
133
- const tilmeld = this;
133
+ /**
134
+ * Check to see if the current user has an ability.
135
+ *
136
+ * If `ability` is undefined, it will check to see if a user is currently
137
+ * logged in.
138
+ *
139
+ * @param ability The ability.
140
+ * @returns Whether the user has the given ability.
141
+ */
142
+ public gatekeeper(ability?: string): boolean {
143
+ if (this.currentUser == null) {
144
+ return false;
145
+ }
146
+ return this.currentUser.$gatekeeper(ability);
147
+ }
134
148
 
149
+ private initAccessControl() {
135
150
  // Check for the skip access control option and add AC selectors.
136
151
  const handleQuery = function (
152
+ nymph: Nymph,
137
153
  options: Options,
138
154
  selectors: FormattedSelector[]
139
155
  ) {
156
+ const tilmeld = nymph.tilmeld as Tilmeld;
140
157
  if (
141
158
  !options ||
142
159
  !('skipAc' in options) ||
@@ -145,20 +162,20 @@ export default class Tilmeld implements TilmeldInterface {
145
162
  ) {
146
163
  if (options?.source === 'client') {
147
164
  if (
148
- !tilmeld.gatekeeper('tilmeld/admin') &&
165
+ !tilmeld.gatekeeper('tilmeld/admin') && // The user is not an admin.
149
166
  ((!tilmeld.config.enableUserSearch &&
150
- options.class?.factorySync() instanceof User) ||
167
+ options.class?.factorySync() instanceof User) || // The use is searching for a user and searching is disabled.
151
168
  (!tilmeld.config.enableGroupSearch &&
152
- options.class?.factorySync() instanceof Group)) &&
153
- (selectors[0] == null ||
154
- selectors[0].type !== '&' ||
155
- (!('guid' in selectors[0]) && !('equal' in selectors[0])) ||
169
+ options.class?.factorySync() instanceof Group)) && // Or the same, but for a group.
170
+ (selectors[0] == null || // No selector specified.
171
+ selectors[0].type !== '&' || // Or the type is not and.
172
+ (!('guid' in selectors[0]) && !('equal' in selectors[0])) || // Or they're searching for something other than guid or equal.
156
173
  ('guid' in selectors[0] &&
157
- selectors[0].guid?.length === 1 &&
158
- typeof selectors[0].guid?.[0] !== 'string') ||
174
+ (!selectors[0].guid?.length ||
175
+ !selectors[0].guid?.[0]?.length)) || // Or they're not searching for a specific guid.
159
176
  ('equal' in selectors[0] &&
160
- selectors[0].equal?.length === 1 &&
161
- selectors[0].equal?.[0]?.[0] !== 'username'))
177
+ selectors[0].equal?.[0]?.[0] !== 'username' &&
178
+ selectors[0].equal?.[0]?.[0] !== 'groupname')) // Or they're not searching for a specific username/groupname.
162
179
  ) {
163
180
  // If the user is not specifically searching for a GUID or username,
164
181
  // and they're not allowed to search, it should fail.
@@ -169,9 +186,14 @@ export default class Tilmeld implements TilmeldInterface {
169
186
  tilmeld.addAccessControlSelectors(options, selectors);
170
187
  }
171
188
  };
189
+ handleQuery.skipOnClone = true;
172
190
 
173
191
  // Filter entities being deleted for user permissions.
174
- const checkPermissionsDelete = function (entity: EntityInterface) {
192
+ const checkPermissionsDelete = function (
193
+ nymph: Nymph,
194
+ entity: EntityInterface
195
+ ) {
196
+ const tilmeld = nymph.tilmeld as Tilmeld;
175
197
  if (
176
198
  typeof entity.$tilmeldDeleteSkipAC === 'function' &&
177
199
  entity.$tilmeldDeleteSkipAC()
@@ -179,30 +201,35 @@ export default class Tilmeld implements TilmeldInterface {
179
201
  return;
180
202
  }
181
203
  // Test for permissions.
182
- if (tilmeld.checkPermissions(entity, Tilmeld.FULL_ACCESS)) {
204
+ if (tilmeld.checkPermissions(entity, TilmeldAccessLevels.FULL_ACCESS)) {
183
205
  throw new AccessControlError('No permission to delete.');
184
206
  }
185
207
  };
208
+ checkPermissionsDelete.skipOnClone = true;
186
209
 
187
210
  // Filter entities being deleted for user permissions.
188
211
  const checkPermissionsDeleteByID = function (
212
+ nymph: Nymph,
189
213
  guid: string,
190
214
  className?: string
191
215
  ) {
192
- const entity = tilmeld.nymph.driver.getEntitySync(
193
- { class: tilmeld.nymph.getEntityClass(className ?? 'Entity') },
216
+ const entity = nymph.driver.getEntitySync(
217
+ { class: nymph.getEntityClass(className ?? 'Entity') },
194
218
  { type: '&', guid: guid }
195
219
  );
196
220
  if (entity != null) {
197
- checkPermissionsDelete(entity);
221
+ checkPermissionsDelete(nymph, entity);
198
222
  }
199
223
  };
224
+ checkPermissionsDeleteByID.skipOnClone = true;
200
225
 
201
226
  // Filter entities being saved for user permissions, and filter any
202
227
  // disallowed changes to AC properties.
203
228
  const checkPermissionsSaveAndFilterAcChanges = function (
229
+ nymph: Nymph,
204
230
  entity: EntityInterface & AccessControlData
205
231
  ) {
232
+ const tilmeld = nymph.tilmeld as Tilmeld;
206
233
  if (!entity) {
207
234
  return;
208
235
  }
@@ -242,7 +269,7 @@ export default class Tilmeld implements TilmeldInterface {
242
269
 
243
270
  // Restore original AC properties and check permissions.
244
271
  setAcProperties(originalAc);
245
- if (tilmeld.checkPermissions(entity, Tilmeld.FULL_ACCESS)) {
272
+ if (tilmeld.checkPermissions(entity, TilmeldAccessLevels.FULL_ACCESS)) {
246
273
  // Only allow changes to AC properties if the user has full access.
247
274
  // TODO: only allow changes to `user` and `group` if tilmeld admin or
248
275
  // group is user's group.
@@ -251,10 +278,11 @@ export default class Tilmeld implements TilmeldInterface {
251
278
  }
252
279
 
253
280
  // Test for permissions.
254
- if (!tilmeld.checkPermissions(entity, Tilmeld.WRITE_ACCESS)) {
281
+ if (!tilmeld.checkPermissions(entity, TilmeldAccessLevels.WRITE_ACCESS)) {
255
282
  throw new AccessControlError('No permission to write.');
256
283
  }
257
284
  };
285
+ checkPermissionsSaveAndFilterAcChanges.skipOnClone = true;
258
286
 
259
287
  /*
260
288
  * Add the current user's "user", "group", and access control to new entity.
@@ -268,11 +296,15 @@ export default class Tilmeld implements TilmeldInterface {
268
296
  *
269
297
  * Default access control is
270
298
  *
271
- * - acUser = Tilmeld::FULL_ACCESS
272
- * - acGroup = Tilmeld::READ_ACCESS
273
- * - acOther = Tilmeld::NO_ACCESS
299
+ * - acUser = TilmeldAccessLevels.FULL_ACCESS
300
+ * - acGroup = TilmeldAccessLevels.READ_ACCESS
301
+ * - acOther = TilmeldAccessLevels.NO_ACCESS
274
302
  */
275
- const addAccess = function (entity: EntityInterface & AccessControlData) {
303
+ const addAccess = function (
304
+ nymph: Nymph,
305
+ entity: EntityInterface & AccessControlData
306
+ ) {
307
+ const tilmeld = nymph.tilmeld as Tilmeld;
276
308
  const user = tilmeld.currentUser;
277
309
  if (
278
310
  user != null &&
@@ -291,13 +323,13 @@ export default class Tilmeld implements TilmeldInterface {
291
323
  entity.group = user.group;
292
324
  }
293
325
  if (entity.acUser == null) {
294
- entity.acUser = Tilmeld.FULL_ACCESS;
326
+ entity.acUser = TilmeldAccessLevels.FULL_ACCESS;
295
327
  }
296
328
  if (entity.acGroup == null) {
297
- entity.acGroup = Tilmeld.READ_ACCESS;
329
+ entity.acGroup = TilmeldAccessLevels.READ_ACCESS;
298
330
  }
299
331
  if (entity.acOther == null) {
300
- entity.acOther = Tilmeld.NO_ACCESS;
332
+ entity.acOther = TilmeldAccessLevels.NO_ACCESS;
301
333
  }
302
334
  if (entity.acRead == null) {
303
335
  entity.acRead = [];
@@ -310,39 +342,53 @@ export default class Tilmeld implements TilmeldInterface {
310
342
  }
311
343
  }
312
344
  };
345
+ addAccess.skipOnClone = true;
313
346
 
314
- const validate = function (entity: EntityInterface & AccessControlData) {
347
+ const validate = function (
348
+ _nymph: Nymph,
349
+ entity: EntityInterface & AccessControlData
350
+ ) {
315
351
  if (!(entity instanceof User) && !(entity instanceof Group)) {
316
352
  const ownershipAcPropertyValidator = (prop: any) => {
317
353
  if (
318
354
  typeof prop != 'number' ||
319
- prop < Tilmeld.NO_ACCESS ||
320
- prop > Tilmeld.FULL_ACCESS
355
+ prop < TilmeldAccessLevels.NO_ACCESS ||
356
+ prop > TilmeldAccessLevels.FULL_ACCESS
321
357
  ) {
322
- throw new AccessControlError('Invalid access control property.');
358
+ throw new AccessControlError(
359
+ 'Invalid access control property: ' + prop
360
+ );
323
361
  }
324
362
  };
325
363
 
326
364
  const accessAcPropertyValidator = (prop: any) => {
327
365
  if (!Array.isArray(prop)) {
328
- throw new AccessControlError('Invalid access control property.');
366
+ throw new AccessControlError(
367
+ 'Invalid access control property: ' + prop
368
+ );
329
369
  }
330
370
  prop.forEach((value) => {
331
371
  if (!(value instanceof User || value instanceof Group)) {
332
- throw new AccessControlError('Invalid access control property.');
372
+ throw new AccessControlError(
373
+ 'Invalid access control property: ' + prop
374
+ );
333
375
  }
334
376
  });
335
377
  };
336
378
 
337
379
  if ('user' in entity) {
338
380
  if (!(entity.user instanceof User)) {
339
- throw new AccessControlError('Invalid access control property.');
381
+ throw new AccessControlError(
382
+ 'Invalid access control property: user'
383
+ );
340
384
  }
341
385
  }
342
386
 
343
387
  if ('group' in entity) {
344
388
  if (!(entity.Group instanceof Group)) {
345
- throw new AccessControlError('Invalid access control property.');
389
+ throw new AccessControlError(
390
+ 'Invalid access control property: group'
391
+ );
346
392
  }
347
393
  }
348
394
 
@@ -366,6 +412,7 @@ export default class Tilmeld implements TilmeldInterface {
366
412
  }
367
413
  }
368
414
  };
415
+ validate.skipOnClone = true;
369
416
 
370
417
  this.nymph.on('query', handleQuery);
371
418
 
@@ -412,7 +459,7 @@ export default class Tilmeld implements TilmeldInterface {
412
459
  selectors.push({
413
460
  type: '|',
414
461
  // Other access control is sufficient.
415
- gte: [['acOther', Tilmeld.READ_ACCESS]],
462
+ gte: [['acOther', TilmeldAccessLevels.READ_ACCESS]],
416
463
  // The user and group are not set.
417
464
  selector: [
418
465
  {
@@ -431,13 +478,13 @@ export default class Tilmeld implements TilmeldInterface {
431
478
  {
432
479
  type: '&',
433
480
  ref: [['user', user]],
434
- gte: [['acUser', Tilmeld.READ_ACCESS]],
481
+ gte: [['acUser', TilmeldAccessLevels.READ_ACCESS]],
435
482
  },
436
483
  ];
437
484
  const selector: FormattedSelector = {
438
485
  type: '|',
439
486
  // Other access control is sufficient.
440
- gte: [['acOther', Tilmeld.READ_ACCESS]],
487
+ gte: [['acOther', TilmeldAccessLevels.READ_ACCESS]],
441
488
  // The user and group are not set.
442
489
  selector: subSelectors,
443
490
  // The user is listed in acRead, acWrite, or acFull.
@@ -481,7 +528,7 @@ export default class Tilmeld implements TilmeldInterface {
481
528
  if (groupRefs.length) {
482
529
  subSelectors.push({
483
530
  type: '&',
484
- gte: [['acGroup', Tilmeld.READ_ACCESS]],
531
+ gte: [['acGroup', TilmeldAccessLevels.READ_ACCESS]],
485
532
  selector: [
486
533
  {
487
534
  type: '|',
@@ -530,9 +577,9 @@ export default class Tilmeld implements TilmeldInterface {
530
577
  *
531
578
  * These properties defaults to:
532
579
  *
533
- * - acUser = Tilmeld.FULL_ACCESS
534
- * - acGroup = Tilmeld.READ_ACCESS
535
- * - acOther = Tilmeld.NO_ACCESS
580
+ * - acUser = TilmeldAccessLevels.FULL_ACCESS
581
+ * - acGroup = TilmeldAccessLevels.READ_ACCESS
582
+ * - acOther = TilmeldAccessLevels.NO_ACCESS
536
583
  *
537
584
  * "acRead", "acWrite", and "acFull" are arrays of users and/or groups that
538
585
  * also have those permissions.
@@ -561,13 +608,13 @@ export default class Tilmeld implements TilmeldInterface {
561
608
  * - None of the above. (Check other AC.)
562
609
  *
563
610
  * @param entity The entity to check.
564
- * @param type The lowest level of permission to consider a pass. One of Tilmeld.READ_ACCESS, Tilmeld.WRITE_ACCESS, or Tilmeld.FULL_ACCESS.
611
+ * @param type The lowest level of permission to consider a pass.
565
612
  * @param user The user to check permissions for. If null, uses the current user. If false, checks for public access.
566
613
  * @returns Whether the current user has at least `type` permission for the entity.
567
614
  */
568
615
  public checkPermissions(
569
616
  entity: EntityInterface & AccessControlData,
570
- type = Tilmeld.READ_ACCESS,
617
+ type: TilmeldAccessLevels = TilmeldAccessLevels.READ_ACCESS,
571
618
  user?: (User & UserData) | false
572
619
  ) {
573
620
  // Only works for entities.
@@ -593,7 +640,8 @@ export default class Tilmeld implements TilmeldInterface {
593
640
  // Users and groups are always readable. Editable by Tilmeld admins.
594
641
  if (
595
642
  (entity instanceof User || entity instanceof Group) &&
596
- (type === Tilmeld.READ_ACCESS || userOrEmpty.$gatekeeper('tilmeld/admin'))
643
+ (type === TilmeldAccessLevels.READ_ACCESS ||
644
+ userOrEmpty.$gatekeeper('tilmeld/admin'))
597
645
  ) {
598
646
  return true;
599
647
  }
@@ -604,9 +652,9 @@ export default class Tilmeld implements TilmeldInterface {
604
652
  }
605
653
 
606
654
  // Load access control, since we need it now...
607
- const acUser = entity.acUser ?? Tilmeld.FULL_ACCESS;
608
- const acGroup = entity.acGroup ?? Tilmeld.READ_ACCESS;
609
- const acOther = entity.acOther ?? Tilmeld.NO_ACCESS;
655
+ const acUser = entity.acUser ?? TilmeldAccessLevels.FULL_ACCESS;
656
+ const acGroup = entity.acGroup ?? TilmeldAccessLevels.READ_ACCESS;
657
+ const acOther = entity.acOther ?? TilmeldAccessLevels.NO_ACCESS;
610
658
 
611
659
  if (userOrNull === null) {
612
660
  return acOther >= type;
@@ -622,7 +670,7 @@ export default class Tilmeld implements TilmeldInterface {
622
670
  userOrEmpty.group != null &&
623
671
  typeof userOrEmpty.group.$is === 'function' &&
624
672
  userOrEmpty.group.$is(entity) &&
625
- type === Tilmeld.READ_ACCESS
673
+ type === TilmeldAccessLevels.READ_ACCESS
626
674
  ) {
627
675
  return true;
628
676
  }
@@ -634,9 +682,18 @@ export default class Tilmeld implements TilmeldInterface {
634
682
 
635
683
  // Check access ac properties.
636
684
  const checks = [
637
- { type: Tilmeld.FULL_ACCESS, array: [...(entity.acFull ?? [])] },
638
- { type: Tilmeld.WRITE_ACCESS, array: [...(entity.acWrite ?? [])] },
639
- { type: Tilmeld.READ_ACCESS, array: [...(entity.acRead ?? [])] },
685
+ {
686
+ type: TilmeldAccessLevels.FULL_ACCESS,
687
+ array: [...(entity.acFull ?? [])],
688
+ },
689
+ {
690
+ type: TilmeldAccessLevels.WRITE_ACCESS,
691
+ array: [...(entity.acWrite ?? [])],
692
+ },
693
+ {
694
+ type: TilmeldAccessLevels.READ_ACCESS,
695
+ array: [...(entity.acRead ?? [])],
696
+ },
640
697
  ];
641
698
  for (let curCheck of checks) {
642
699
  if (type <= curCheck.type) {
@@ -672,6 +729,73 @@ export default class Tilmeld implements TilmeldInterface {
672
729
  return acOther >= type;
673
730
  }
674
731
 
732
+ /**
733
+ * Check a UID's permissions for a user.
734
+ *
735
+ * ## THIS ONLY CHECKS AUTOMATICALLY FOR CLIENT REQUESTS.
736
+ *
737
+ * UID functions on the Node.js side are not checked automatically. This
738
+ * function is only run automatically for UID functions run from the client.
739
+ * You should call this function manually if you're running a UID function on
740
+ * the Node.js side and you want it gated.
741
+ *
742
+ * This will check the Tilmeld config and the user's abilities.
743
+ *
744
+ * - READ_ACCESS, the UID is listed in clientReadableUIDs or the user has the
745
+ * "uid/get/nameofuid" ability.
746
+ * - WRITE_ACCESS, the UID is listed in clientEnabledUIDs or the user has the
747
+ * "uid/new/nameofuid" ability.
748
+ * - FULL_ACCESS, the UID is listed in clientSetabledUIDs or the user has the
749
+ * "uid/set/nameofuid" ability.
750
+ *
751
+ * @param name The UID to check.
752
+ * @param type The lowest level of permission to consider a pass.
753
+ * @param user The user to check permissions for. If null, uses the current user. If false, checks for public access.
754
+ * @returns Whether the current user has at least `type` permission for the UID.
755
+ */
756
+ public checkClientUIDPermissions(
757
+ name: string,
758
+ type: TilmeldAccessLevels = TilmeldAccessLevels.READ_ACCESS,
759
+ user?: (User & UserData) | false
760
+ ) {
761
+ let userOrEmpty: User & UserData = this.User.factorySync();
762
+ // Calculate the user.
763
+ if (user == null) {
764
+ userOrEmpty = this.User.current(true);
765
+ } else if (user !== false) {
766
+ userOrEmpty = user;
767
+ }
768
+
769
+ if (userOrEmpty.$gatekeeper('system/admin')) {
770
+ return true;
771
+ }
772
+
773
+ if (type === TilmeldAccessLevels.FULL_ACCESS) {
774
+ return (
775
+ this.config.clientSetabledUIDs.indexOf(name) !== -1 ||
776
+ userOrEmpty.$gatekeeper(`uid/set/${name}`)
777
+ );
778
+ } else if (type === TilmeldAccessLevels.WRITE_ACCESS) {
779
+ return (
780
+ this.config.clientEnabledUIDs.indexOf(name) !== -1 ||
781
+ this.config.clientSetabledUIDs.indexOf(name) !== -1 ||
782
+ userOrEmpty.$gatekeeper(`uid/new/${name}`) ||
783
+ userOrEmpty.$gatekeeper(`uid/set/${name}`)
784
+ );
785
+ } else if (type === TilmeldAccessLevels.READ_ACCESS) {
786
+ return (
787
+ this.config.clientReadableUIDs.indexOf(name) !== -1 ||
788
+ this.config.clientEnabledUIDs.indexOf(name) !== -1 ||
789
+ this.config.clientSetabledUIDs.indexOf(name) !== -1 ||
790
+ userOrEmpty.$gatekeeper(`uid/get/${name}`) ||
791
+ userOrEmpty.$gatekeeper(`uid/new/${name}`) ||
792
+ userOrEmpty.$gatekeeper(`uid/set/${name}`)
793
+ );
794
+ }
795
+
796
+ return false;
797
+ }
798
+
675
799
  /**
676
800
  * Fill session user data.
677
801
  *
@@ -754,9 +878,9 @@ export default class Tilmeld implements TilmeldInterface {
754
878
  // to provide the auth token.
755
879
  let fromAuthHeader = false;
756
880
  let authToken: string;
757
- if (this.request.header('HTTP_X_TILMELDAUTH') != null) {
881
+ if (this.request.header('x-tilmeldauth') != null) {
758
882
  fromAuthHeader = true;
759
- authToken = this.request.header('HTTP_X_TILMELDAUTH') as string;
883
+ authToken = this.request.header('x-tilmeldauth') as string;
760
884
  } else if ('TILMELDAUTH' in cookies) {
761
885
  fromAuthHeader = false;
762
886
  authToken = cookies.TILMELDAUTH;
@@ -775,7 +899,7 @@ export default class Tilmeld implements TilmeldInterface {
775
899
  } else {
776
900
  // The request is for something else, so check for a valid XSRF token,
777
901
  // unless the auth token is provided by a header (instead of a cookie).
778
- const xsrfToken = this.request.header('HTTP_X_XSRF_TOKEN');
902
+ const xsrfToken = this.request.header('x-xsrf-token');
779
903
  if (xsrfToken == null && !fromAuthHeader) {
780
904
  return false;
781
905
  }
package/src/User.test.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { SQLite3Driver } from '@nymphjs/driver-sqlite3';
2
- import nymph from '@nymphjs/nymph';
2
+ import { Nymph } from '@nymphjs/nymph';
3
3
 
4
4
  import Tilmeld from './Tilmeld';
5
5
  import defaults from './conf/defaults';
@@ -16,7 +16,7 @@ const tilmeld = new Tilmeld({
16
16
  cancelChangeRedirect: 'http://localhost:8080',
17
17
  jwtSecret: 'shhhhh',
18
18
  });
19
- nymph.init(
19
+ const _nymph = new Nymph(
20
20
  {},
21
21
  new SQLite3Driver({
22
22
  filename: ':memory:',
@@ -40,6 +40,14 @@ describe('User', () => {
40
40
  return newUser;
41
41
  }
42
42
 
43
+ it('new user passes validation', async () => {
44
+ const validUser = await makeNewUser();
45
+
46
+ expect(() => {
47
+ defaults.validatorUser(validUser);
48
+ }).not.toThrow();
49
+ });
50
+
43
51
  it("doesn't allow unknown keys", async () => {
44
52
  const invalidUser = await makeNewUser();
45
53
 
package/src/User.ts CHANGED
@@ -14,9 +14,9 @@ import sha256 from 'crypto-js/sha256';
14
14
  import md5 from 'crypto-js/md5';
15
15
  import { difference } from 'lodash';
16
16
 
17
+ import type Tilmeld from './Tilmeld';
17
18
  import AbleObject from './AbleObject';
18
19
  import Group, { GroupData } from './Group';
19
- import Tilmeld from './Tilmeld';
20
20
  import {
21
21
  BadDataError,
22
22
  BadEmailError,
@@ -126,11 +126,20 @@ export type UserData = {
126
126
  passwordTemp?: string;
127
127
  };
128
128
 
129
+ /**
130
+ * A user data model.
131
+ *
132
+ * Written by Hunter Perrin for SciActive.
133
+ *
134
+ * @author Hunter Perrin <hperrin@gmail.com>
135
+ * @copyright SciActive Inc
136
+ * @see http://nymph.io/
137
+ */
129
138
  export default class User extends AbleObject<UserData> {
130
139
  /**
131
140
  * The instance of Tilmeld to use for queries.
132
141
  */
133
- public static tilmeld: Tilmeld;
142
+ static tilmeld: Tilmeld;
134
143
  static ETYPE = 'tilmeld_user';
135
144
  static class = 'User';
136
145
 
package/src/conf/d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { EmailOptions } from 'email-templates';
2
+
2
3
  import type Tilmeld from '../Tilmeld';
3
4
  import Group, { GroupData } from '../Group';
4
5
  import User, { UserData } from '../User';
@@ -64,6 +65,35 @@ export interface Config {
64
65
  * a concern. Same risks as user search if generatePrimary is true.)
65
66
  */
66
67
  enableGroupSearch: boolean;
68
+ /**
69
+ * A list of UIDs that can be read from the client by anyone. (getUID)
70
+ *
71
+ * Note: If you'd like to limit the access to logged in users, give them an
72
+ * ability like "uid/get/nameofuid".
73
+ */
74
+ clientReadableUIDs: string[];
75
+ /**
76
+ * A list of UIDs that can be created from the client by anyone. (newUID)
77
+ *
78
+ * Inclusion in this list implies inclusion in clientReadableUIDs.
79
+ *
80
+ * Note: If you'd like to limit the access to logged in users, give them an
81
+ * ability like "uid/new/nameofuid".
82
+ */
83
+ clientEnabledUIDs: string[];
84
+ /**
85
+ * A list of UIDs that can be set from the client by anyone. (setUID,
86
+ * renameUID)
87
+ *
88
+ * Inclusion in this list implies inclusion in clientReadableUIDs and
89
+ * clientEnabledUIDs.
90
+ *
91
+ * Note: There is no way to run renameUID from the client.
92
+ *
93
+ * Note: If you'd like to limit the access to logged in users, give them an
94
+ * ability like "uid/set/nameofuid".
95
+ */
96
+ clientSetabledUIDs: string[];
67
97
  /**
68
98
  * These will be the available fields for users. (Some fields, like username,
69
99
  * can't be excluded.)