@roeehrl/tinode-sdk 0.25.1-sqlite.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.
@@ -0,0 +1,567 @@
1
+ /**
2
+ * @file Access control model.
3
+ *
4
+ * @copyright 2015-2022 Tinode LLC.
5
+ */
6
+ 'use strict';
7
+
8
+ // NOTE TO DEVELOPERS:
9
+ // Localizable strings should be double quoted "строка на другом языке",
10
+ // non-localizable strings should be single quoted 'non-localized'.
11
+
12
+ /**
13
+ * Helper class for handling access mode.
14
+ *
15
+ * @class AccessMode
16
+ * @memberof Tinode
17
+ *
18
+ * @param {AccessMode|Object=} acs - AccessMode to copy or access mode object received from the server.
19
+ */
20
+ export default class AccessMode {
21
+ constructor(acs) {
22
+ if (acs) {
23
+ this.given = typeof acs.given == 'number' ? acs.given : AccessMode.decode(acs.given);
24
+ this.want = typeof acs.want == 'number' ? acs.want : AccessMode.decode(acs.want);
25
+ this.mode = acs.mode ? (typeof acs.mode == 'number' ? acs.mode : AccessMode.decode(acs.mode)) :
26
+ (this.given & this.want);
27
+ }
28
+ }
29
+
30
+ static #checkFlag(val, side, flag) {
31
+ side = side || 'mode';
32
+ if (['given', 'want', 'mode'].includes(side)) {
33
+ return ((val[side] & flag) != 0);
34
+ }
35
+ throw new Error(`Invalid AccessMode component '${side}'`);
36
+ }
37
+ /**
38
+ * Parse string into an access mode value.
39
+ * @memberof Tinode.AccessMode
40
+ * @static
41
+ *
42
+ * @param {string | Number} mode - either a String representation of the access mode to parse or a set of bits to assign.
43
+ * @returns {number} - Access mode as a numeric value.
44
+ */
45
+ static decode(str) {
46
+ if (!str) {
47
+ return null;
48
+ } else if (typeof str == 'number') {
49
+ return str & AccessMode._BITMASK;
50
+ } else if (str === 'N' || str === 'n') {
51
+ return AccessMode._NONE;
52
+ }
53
+
54
+ const bitmask = {
55
+ 'J': AccessMode._JOIN,
56
+ 'R': AccessMode._READ,
57
+ 'W': AccessMode._WRITE,
58
+ 'P': AccessMode._PRES,
59
+ 'A': AccessMode._APPROVE,
60
+ 'S': AccessMode._SHARE,
61
+ 'D': AccessMode._DELETE,
62
+ 'O': AccessMode._OWNER
63
+ };
64
+
65
+ let m0 = AccessMode._NONE;
66
+
67
+ for (let i = 0; i < str.length; i++) {
68
+ const bit = bitmask[str.charAt(i).toUpperCase()];
69
+ if (!bit) {
70
+ // Unrecognized bit, skip.
71
+ continue;
72
+ }
73
+ m0 |= bit;
74
+ }
75
+ return m0;
76
+ }
77
+ /**
78
+ * Convert numeric representation of the access mode into a string.
79
+ *
80
+ * @memberof Tinode.AccessMode
81
+ * @static
82
+ *
83
+ * @param {number} val - access mode value to convert to a string.
84
+ * @returns {string} - Access mode as a string.
85
+ */
86
+ static encode(val) {
87
+ if (val === null || val === AccessMode._INVALID) {
88
+ return null;
89
+ } else if (val === AccessMode._NONE) {
90
+ return 'N';
91
+ }
92
+
93
+ const bitmask = ['J', 'R', 'W', 'P', 'A', 'S', 'D', 'O'];
94
+ let res = '';
95
+ for (let i = 0; i < bitmask.length; i++) {
96
+ if ((val & (1 << i)) != 0) {
97
+ res = res + bitmask[i];
98
+ }
99
+ }
100
+ return res;
101
+ }
102
+ /**
103
+ * Update numeric representation of access mode with the new value. The value
104
+ * is one of the following:
105
+ * - a string starting with <code>'+'</code> or <code>'-'</code> then the bits to add or remove, e.g. <code>'+R-W'</code> or <code>'-PS'</code>.
106
+ * - a new value of access mode
107
+ *
108
+ * @memberof Tinode.AccessMode
109
+ * @static
110
+ *
111
+ * @param {number} val - access mode value to update.
112
+ * @param {string} upd - update to apply to val.
113
+ * @returns {number} - updated access mode.
114
+ */
115
+ static update(val, upd) {
116
+ if (!upd || typeof upd != 'string') {
117
+ return val;
118
+ }
119
+
120
+ let action = upd.charAt(0);
121
+ if (action == '+' || action == '-') {
122
+ let val0 = val;
123
+ // Split delta-string like '+ABC-DEF+Z' into an array of parts including + and -.
124
+ const parts = upd.split(/([-+])/);
125
+ // Starting iteration from 1 because String.split() creates an array with the first empty element.
126
+ // Iterating by 2 because we parse pairs +/- then data.
127
+ for (let i = 1; i < parts.length - 1; i += 2) {
128
+ action = parts[i];
129
+ const m0 = AccessMode.decode(parts[i + 1]);
130
+ if (m0 == AccessMode._INVALID) {
131
+ return val;
132
+ }
133
+ if (m0 == null) {
134
+ continue;
135
+ }
136
+ if (action === '+') {
137
+ val0 |= m0;
138
+ } else if (action === '-') {
139
+ val0 &= ~m0;
140
+ }
141
+ }
142
+ val = val0;
143
+ } else {
144
+ // The string is an explicit new value 'ABC' rather than delta.
145
+ const val0 = AccessMode.decode(upd);
146
+ if (val0 != AccessMode._INVALID) {
147
+ val = val0;
148
+ }
149
+ }
150
+
151
+ return val;
152
+ }
153
+ /**
154
+ * Bits present in a1 but missing in a2.
155
+ *
156
+ * @static
157
+ * @memberof Tinode
158
+ *
159
+ * @param {number | string} a1 - access mode to subtract from.
160
+ * @param {number | string} a2 - access mode to subtract.
161
+ * @returns {number} access mode with bits present in <code>a1</code> but missing in <code>a2</code>.
162
+ */
163
+ static diff(a1, a2) {
164
+ a1 = AccessMode.decode(a1);
165
+ a2 = AccessMode.decode(a2);
166
+
167
+ if (a1 == AccessMode._INVALID || a2 == AccessMode._INVALID) {
168
+ return AccessMode._INVALID;
169
+ }
170
+ return a1 & ~a2;
171
+ }
172
+ /**
173
+ * AccessMode is a class representing topic access mode.
174
+ *
175
+ * @memberof Tinode
176
+ * @class AccessMode
177
+ */
178
+ /**
179
+ * Custom formatter
180
+ */
181
+ toString() {
182
+ return '{"mode": "' + AccessMode.encode(this.mode) +
183
+ '", "given": "' + AccessMode.encode(this.given) +
184
+ '", "want": "' + AccessMode.encode(this.want) + '"}';
185
+ }
186
+ /**
187
+ * AccessMode is a class representing topic access mode.
188
+ *
189
+ * @memberof Tinode
190
+ * @class AccessMode
191
+ */
192
+ /**
193
+ * Converts numeric values to strings.
194
+ */
195
+ jsonHelper() {
196
+ return {
197
+ mode: AccessMode.encode(this.mode),
198
+ given: AccessMode.encode(this.given),
199
+ want: AccessMode.encode(this.want)
200
+ };
201
+ }
202
+ /**
203
+ * AccessMode is a class representing topic access mode.
204
+ *
205
+ * @memberof Tinode
206
+ * @class AccessMode
207
+ */
208
+ /**
209
+ * Assign value to 'mode'.
210
+ * @memberof Tinode.AccessMode
211
+ *
212
+ * @param {string | Number} m - either a string representation of the access mode or a set of bits.
213
+ * @returns {AccessMode} - <code>this</code> AccessMode.
214
+ */
215
+ setMode(m) {
216
+ this.mode = AccessMode.decode(m);
217
+ return this;
218
+ }
219
+ /**
220
+ * AccessMode is a class representing topic access mode.
221
+ *
222
+ * @memberof Tinode
223
+ * @class AccessMode
224
+ */
225
+ /**
226
+ * Update <code>mode</code> value.
227
+ * @memberof Tinode.AccessMode
228
+ *
229
+ * @param {string} u - string representation of the changes to apply to access mode.
230
+ * @returns {AccessMode} - <code>this</code> AccessMode.
231
+ */
232
+ updateMode(u) {
233
+ this.mode = AccessMode.update(this.mode, u);
234
+ return this;
235
+ }
236
+ /**
237
+ * AccessMode is a class representing topic access mode.
238
+ *
239
+ * @memberof Tinode
240
+ * @class AccessMode
241
+ */
242
+ /**
243
+ * Get <code>mode</code> value as a string.
244
+ * @memberof Tinode.AccessMode
245
+ *
246
+ * @returns {string} - <code>mode</code> value.
247
+ */
248
+ getMode() {
249
+ return AccessMode.encode(this.mode);
250
+ }
251
+ /**
252
+ * AccessMode is a class representing topic access mode.
253
+ *
254
+ * @memberof Tinode
255
+ * @class AccessMode
256
+ */
257
+ /**
258
+ * Assign <code>given</code> value.
259
+ * @memberof Tinode.AccessMode
260
+ *
261
+ * @param {string | Number} g - either a string representation of the access mode or a set of bits.
262
+ * @returns {AccessMode} - <code>this</code> AccessMode.
263
+ */
264
+ setGiven(g) {
265
+ this.given = AccessMode.decode(g);
266
+ return this;
267
+ }
268
+ /**
269
+ * AccessMode is a class representing topic access mode.
270
+ *
271
+ * @memberof Tinode
272
+ * @class AccessMode
273
+ */
274
+ /**
275
+ * Update 'given' value.
276
+ * @memberof Tinode.AccessMode
277
+ *
278
+ * @param {string} u - string representation of the changes to apply to access mode.
279
+ * @returns {AccessMode} - <code>this</code> AccessMode.
280
+ */
281
+ updateGiven(u) {
282
+ this.given = AccessMode.update(this.given, u);
283
+ return this;
284
+ }
285
+ /**
286
+ * AccessMode is a class representing topic access mode.
287
+ *
288
+ * @memberof Tinode
289
+ * @class AccessMode
290
+ */
291
+ /**
292
+ * Get 'given' value as a string.
293
+ * @memberof Tinode.AccessMode
294
+ *
295
+ * @returns {string} - <b>given</b> value.
296
+ */
297
+ getGiven() {
298
+ return AccessMode.encode(this.given);
299
+ }
300
+ /**
301
+ * AccessMode is a class representing topic access mode.
302
+ *
303
+ * @memberof Tinode
304
+ * @class AccessMode
305
+ */
306
+ /**
307
+ * Assign 'want' value.
308
+ * @memberof Tinode.AccessMode
309
+ *
310
+ * @param {string | Number} w - either a string representation of the access mode or a set of bits.
311
+ * @returns {AccessMode} - <code>this</code> AccessMode.
312
+ */
313
+ setWant(w) {
314
+ this.want = AccessMode.decode(w);
315
+ return this;
316
+ }
317
+ /**
318
+ * AccessMode is a class representing topic access mode.
319
+ *
320
+ * @memberof Tinode
321
+ * @class AccessMode
322
+ */
323
+ /**
324
+ * Update 'want' value.
325
+ * @memberof Tinode.AccessMode
326
+ *
327
+ * @param {string} u - string representation of the changes to apply to access mode.
328
+ * @returns {AccessMode} - <code>this</code> AccessMode.
329
+ */
330
+ updateWant(u) {
331
+ this.want = AccessMode.update(this.want, u);
332
+ return this;
333
+ }
334
+ /**
335
+ * AccessMode is a class representing topic access mode.
336
+ *
337
+ * @memberof Tinode
338
+ * @class AccessMode
339
+ */
340
+ /**
341
+ * Get 'want' value as a string.
342
+ * @memberof Tinode.AccessMode
343
+ *
344
+ * @returns {string} - <b>want</b> value.
345
+ */
346
+ getWant() {
347
+ return AccessMode.encode(this.want);
348
+ }
349
+ /**
350
+ * AccessMode is a class representing topic access mode.
351
+ *
352
+ * @memberof Tinode
353
+ * @class AccessMode
354
+ */
355
+ /**
356
+ * Get permissions present in 'want' but missing in 'given'.
357
+ * Inverse of {@link Tinode.AccessMode#getExcessive}
358
+ *
359
+ * @memberof Tinode.AccessMode
360
+ *
361
+ * @returns {string} permissions present in <b>want</b> but missing in <b>given</b>.
362
+ */
363
+ getMissing() {
364
+ return AccessMode.encode(this.want & ~this.given);
365
+ }
366
+ /**
367
+ * AccessMode is a class representing topic access mode.
368
+ *
369
+ * @memberof Tinode
370
+ * @class AccessMode
371
+ */
372
+ /**
373
+ * Get permissions present in 'given' but missing in 'want'.
374
+ * Inverse of {@link Tinode.AccessMode#getMissing}
375
+ * @memberof Tinode.AccessMode
376
+ *
377
+ * @returns {string} permissions present in <b>given</b> but missing in <b>want</b>.
378
+ */
379
+ getExcessive() {
380
+ return AccessMode.encode(this.given & ~this.want);
381
+ }
382
+ /**
383
+ * AccessMode is a class representing topic access mode.
384
+ *
385
+ * @memberof Tinode
386
+ * @class AccessMode
387
+ */
388
+ /**
389
+ * Update 'want', 'give', and 'mode' values.
390
+ * @memberof Tinode.AccessMode
391
+ *
392
+ * @param {AccessMode} val - new access mode value.
393
+ * @returns {AccessMode} - <code>this</code> AccessMode.
394
+ */
395
+ updateAll(val) {
396
+ if (val) {
397
+ this.updateGiven(val.given);
398
+ this.updateWant(val.want);
399
+ this.mode = this.given & this.want;
400
+ }
401
+ return this;
402
+ }
403
+ /**
404
+ * AccessMode is a class representing topic access mode.
405
+ *
406
+ * @memberof Tinode
407
+ * @class AccessMode
408
+ */
409
+ /**
410
+ * Check if Owner (O) flag is set.
411
+ * @memberof Tinode.AccessMode
412
+ * @param {string=} side - which permission to check: given, want, mode; default: mode.
413
+ * @returns {boolean} - <code>true</code> if flag is set.
414
+ */
415
+ isOwner(side) {
416
+ return AccessMode.#checkFlag(this, side, AccessMode._OWNER);
417
+ }
418
+ /**
419
+ * AccessMode is a class representing topic access mode.
420
+ *
421
+ * @memberof Tinode
422
+ * @class AccessMode
423
+ */
424
+ /**
425
+ * Check if Presence (P) flag is set.
426
+ * @memberof Tinode.AccessMode
427
+ * @param {string=} side - which permission to check: given, want, mode; default: mode.
428
+ * @returns {boolean} - <code>true</code> if flag is set.
429
+ */
430
+ isPresencer(side) {
431
+ return AccessMode.#checkFlag(this, side, AccessMode._PRES);
432
+ }
433
+ /**
434
+ * AccessMode is a class representing topic access mode.
435
+ *
436
+ * @memberof Tinode
437
+ * @class AccessMode
438
+ */
439
+ /**
440
+ * Check if Presence (P) flag is NOT set.
441
+ * @memberof Tinode.AccessMode
442
+ * @param {string=} side - which permission to check: given, want, mode; default: mode.
443
+ * @returns {boolean} - <code>true</code> if flag is set.
444
+ */
445
+ isMuted(side) {
446
+ return !this.isPresencer(side);
447
+ }
448
+ /**
449
+ * AccessMode is a class representing topic access mode.
450
+ *
451
+ * @memberof Tinode
452
+ * @class AccessMode
453
+ */
454
+ /**
455
+ * Check if Join (J) flag is set.
456
+ * @memberof Tinode.AccessMode
457
+ * @param {string=} side - which permission to check: given, want, mode; default: mode.
458
+ * @returns {boolean} - <code>true</code> if flag is set.
459
+ */
460
+ isJoiner(side) {
461
+ return AccessMode.#checkFlag(this, side, AccessMode._JOIN);
462
+ }
463
+ /**
464
+ * AccessMode is a class representing topic access mode.
465
+ *
466
+ * @memberof Tinode
467
+ * @class AccessMode
468
+ */
469
+ /**
470
+ * Check if Reader (R) flag is set.
471
+ * @memberof Tinode.AccessMode
472
+ * @param {string=} side - which permission to check: given, want, mode; default: mode.
473
+ * @returns {boolean} - <code>true</code> if flag is set.
474
+ */
475
+ isReader(side) {
476
+ return AccessMode.#checkFlag(this, side, AccessMode._READ);
477
+ }
478
+ /**
479
+ * AccessMode is a class representing topic access mode.
480
+ *
481
+ * @memberof Tinode
482
+ * @class AccessMode
483
+ */
484
+ /**
485
+ * Check if Writer (W) flag is set.
486
+ * @memberof Tinode.AccessMode
487
+ * @param {string=} side - which permission to check: given, want, mode; default: mode.
488
+ * @returns {boolean} - <code>true</code> if flag is set.
489
+ */
490
+ isWriter(side) {
491
+ return AccessMode.#checkFlag(this, side, AccessMode._WRITE);
492
+ }
493
+ /**
494
+ * AccessMode is a class representing topic access mode.
495
+ *
496
+ * @memberof Tinode
497
+ * @class AccessMode
498
+ */
499
+ /**
500
+ * Check if Approver (A) flag is set.
501
+ * @memberof Tinode.AccessMode
502
+ * @param {string=} side - which permission to check: given, want, mode; default: mode.
503
+ * @returns {boolean} - <code>true</code> if flag is set.
504
+ */
505
+ isApprover(side) {
506
+ return AccessMode.#checkFlag(this, side, AccessMode._APPROVE);
507
+ }
508
+ /**
509
+ * AccessMode is a class representing topic access mode.
510
+ *
511
+ * @memberof Tinode
512
+ * @class AccessMode
513
+ */
514
+ /**
515
+ * Check if either one of Owner (O) or Approver (A) flags is set.
516
+ * @memberof Tinode.AccessMode
517
+ * @param {string=} side - which permission to check: given, want, mode; default: mode.
518
+ * @returns {boolean} - <code>true</code> if flag is set.
519
+ */
520
+ isAdmin(side) {
521
+ return this.isOwner(side) || this.isApprover(side);
522
+ }
523
+ /**
524
+ * AccessMode is a class representing topic access mode.
525
+ *
526
+ * @memberof Tinode
527
+ * @class AccessMode
528
+ */
529
+ /**
530
+ * Check if either one of Owner (O), Approver (A), or Sharer (S) flags is set.
531
+ * @memberof Tinode.AccessMode
532
+ * @param {string=} side - which permission to check: given, want, mode; default: mode.
533
+ * @returns {boolean} - <code>true</code> if flag is set.
534
+ */
535
+ isSharer(side) {
536
+ return this.isAdmin(side) || AccessMode.#checkFlag(this, side, AccessMode._SHARE);
537
+ }
538
+ /**
539
+ * AccessMode is a class representing topic access mode.
540
+ *
541
+ * @memberof Tinode
542
+ * @class AccessMode
543
+ */
544
+ /**
545
+ * Check if Deleter (D) flag is set.
546
+ * @memberof Tinode.AccessMode
547
+ * @param {string=} side - which permission to check: given, want, mode; default: mode.
548
+ * @returns {boolean} - <code>true</code> if flag is set.
549
+ */
550
+ isDeleter(side) {
551
+ return AccessMode.#checkFlag(this, side, AccessMode._DELETE);
552
+ }
553
+ }
554
+
555
+ AccessMode._NONE = 0x00;
556
+ AccessMode._JOIN = 0x01;
557
+ AccessMode._READ = 0x02;
558
+ AccessMode._WRITE = 0x04;
559
+ AccessMode._PRES = 0x08;
560
+ AccessMode._APPROVE = 0x10;
561
+ AccessMode._SHARE = 0x20;
562
+ AccessMode._DELETE = 0x40;
563
+ AccessMode._OWNER = 0x80;
564
+
565
+ AccessMode._BITMASK = AccessMode._JOIN | AccessMode._READ | AccessMode._WRITE | AccessMode._PRES |
566
+ AccessMode._APPROVE | AccessMode._SHARE | AccessMode._DELETE | AccessMode._OWNER;
567
+ AccessMode._INVALID = 0x100000;