1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.github.tonywasher.joceanus.prometheus.data;
18
19 import io.github.tonywasher.joceanus.gordianknot.api.factory.GordianFactory;
20 import io.github.tonywasher.joceanus.gordianknot.api.factory.GordianFactory.GordianFactoryLock;
21 import io.github.tonywasher.joceanus.gordianknot.util.GordianUtilities;
22 import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataList;
23 import io.github.tonywasher.joceanus.metis.data.MetisDataResource;
24 import io.github.tonywasher.joceanus.metis.field.MetisFieldItem;
25 import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
26 import io.github.tonywasher.joceanus.metis.field.MetisFieldVersionedSet;
27 import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
28 import io.github.tonywasher.joceanus.oceanus.date.OceanusDate;
29 import io.github.tonywasher.joceanus.oceanus.format.OceanusDataFormatter;
30 import io.github.tonywasher.joceanus.prometheus.data.PrometheusControlKeySet.PrometheusControlKeySetList;
31 import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataSet.PrometheusCryptographyDataType;
32 import io.github.tonywasher.joceanus.prometheus.exc.PrometheusDataException;
33 import io.github.tonywasher.joceanus.prometheus.security.PrometheusSecurityPasswordManager;
34
35 import java.util.ArrayList;
36 import java.util.Iterator;
37 import java.util.List;
38
39
40
41
42
43
44
45 public final class PrometheusControlKey
46 extends PrometheusDataItem {
47
48
49
50 public static final String OBJECT_NAME = PrometheusCryptographyDataType.CONTROLKEY.getItemName();
51
52
53
54
55 public static final String LIST_NAME = PrometheusCryptographyDataType.CONTROLKEY.getListName();
56
57
58
59
60 public static final int LOCKLEN = GordianUtilities.getFactoryLockLen();
61
62
63
64
65 private static final MetisFieldVersionedSet<PrometheusControlKey> FIELD_DEFS = MetisFieldVersionedSet.newVersionedFieldSet(PrometheusControlKey.class);
66
67
68
69
70 static {
71 FIELD_DEFS.declareByteArrayField(PrometheusDataResource.CONTROLKEY_LOCKBYTES, LOCKLEN);
72 FIELD_DEFS.declareDateField(PrometheusDataResource.CONTROLKEY_CREATION);
73 FIELD_DEFS.declareDerivedVersionedField(PrometheusDataResource.CONTROLKEY_LOCK);
74 FIELD_DEFS.declareLocalField(PrometheusDataResource.CONTROLKEYSET_LIST, PrometheusControlKey::getControlKeySets);
75 }
76
77
78
79
80 public static final String NAME_DATABASE = PrometheusDataResource.CONTROLKEY_DATABASE.getValue();
81
82
83
84
85 private ControlKeySetCache theKeySetCache = new ControlKeySetCache();
86
87
88
89
90
91
92
93 private PrometheusControlKey(final PrometheusControlKeyList pList,
94 final PrometheusControlKey pSource) {
95
96 super(pList, pSource);
97 }
98
99
100
101
102
103
104
105
106 private PrometheusControlKey(final PrometheusControlKeyList pList,
107 final PrometheusDataValues pValues) throws OceanusException {
108
109 super(pList, pValues);
110
111
112 try {
113
114 Object myValue = pValues.getValue(PrometheusDataResource.CONTROLKEY_LOCKBYTES);
115 if (myValue instanceof byte[] ba) {
116 setValueFactoryLockBytes(ba);
117 }
118
119
120 myValue = pValues.getValue(PrometheusDataResource.CONTROLKEY_LOCK);
121 if (myValue instanceof GordianFactoryLock l) {
122 setValueFactoryLock(l);
123 } else if (getLockBytes() != null) {
124
125 final PrometheusDataSet myData = getDataSet();
126 final PrometheusSecurityPasswordManager myPasswordMgr = myData.getPasswordMgr();
127
128
129 final GordianFactoryLock myLock = myPasswordMgr.resolveFactoryLock(getLockBytes(), NAME_DATABASE);
130
131
132 setValueFactoryLock(myLock);
133 }
134
135
136 myValue = pValues.getValue(PrometheusDataResource.CONTROLKEY_CREATION);
137 if (!(myValue instanceof OceanusDate)) {
138 myValue = new OceanusDate();
139 }
140 setValueCreationDate((OceanusDate) myValue);
141
142
143 } catch (OceanusException e) {
144
145 throw new PrometheusDataException(this, ERROR_CREATEITEM, e);
146 }
147 }
148
149
150
151
152
153
154
155
156
157 private PrometheusControlKey(final PrometheusControlKeyList pList) throws OceanusException {
158
159 super(pList, 0);
160
161
162 try {
163
164 final PrometheusDataSet myData = getDataSet();
165 final PrometheusSecurityPasswordManager myPasswordMgr = myData.getPasswordMgr();
166
167
168 final GordianFactoryLock myLock = myPasswordMgr.newFactoryLock(NAME_DATABASE);
169
170
171 setValueFactoryLockBytes(myLock.getLockBytes());
172 setValueFactoryLock(myLock);
173
174
175 allocateControlKeySets(myData);
176
177
178 setValueCreationDate(new OceanusDate());
179
180
181 } catch (OceanusException e) {
182
183 throw new PrometheusDataException(this, ERROR_CREATEITEM, e);
184 }
185 }
186
187
188
189
190
191
192
193
194
195 private PrometheusControlKey(final PrometheusControlKey pKey) throws OceanusException {
196
197 super(pKey.getList(), 0);
198
199
200 try {
201
202 final PrometheusDataSet myData = getDataSet();
203 final PrometheusSecurityPasswordManager myPasswordMgr = myData.getPasswordMgr();
204
205
206 final GordianFactory myFactory = myPasswordMgr.getSecurityFactory();
207 myFactory.reSeedRandom();
208
209
210 final GordianFactoryLock myLock = myPasswordMgr.similarFactoryLock(pKey.getFactoryLock());
211
212
213 setValueFactoryLockBytes(myLock.getLockBytes());
214 setValueFactoryLock(myLock);
215
216
217 allocateControlKeySets(myData);
218
219
220 } catch (OceanusException e) {
221
222 throw new PrometheusDataException(this, ERROR_CREATEITEM, e);
223 }
224 }
225
226 @Override
227 public MetisFieldSetDef getDataFieldSet() {
228 return FIELD_DEFS;
229 }
230
231
232
233
234
235
236 private ControlKeySetCache getControlKeySets() {
237 return theKeySetCache;
238 }
239
240
241
242
243
244
245 public byte[] getLockBytes() {
246 return getValues().getValue(PrometheusDataResource.CONTROLKEY_LOCKBYTES, byte[].class);
247 }
248
249
250
251
252
253
254 public GordianFactoryLock getFactoryLock() {
255 return getValues().getValue(PrometheusDataResource.CONTROLKEY_LOCK, GordianFactoryLock.class);
256 }
257
258
259
260
261
262
263 public GordianFactory getSecurityFactory() {
264 final GordianFactoryLock myLock = getFactoryLock();
265 return myLock == null ? null : myLock.getFactory();
266 }
267
268
269
270
271
272
273 public OceanusDate getCreationDate() {
274 return getValues().getValue(PrometheusDataResource.CONTROLKEY_CREATION, OceanusDate.class);
275 }
276
277
278
279
280
281
282
283 private void setValueFactoryLockBytes(final byte[] pValue) throws OceanusException {
284 getValues().setValue(PrometheusDataResource.CONTROLKEY_LOCKBYTES, pValue);
285 }
286
287
288
289
290
291
292
293 private void setValueFactoryLock(final GordianFactoryLock pValue) throws OceanusException {
294 getValues().setValue(PrometheusDataResource.CONTROLKEY_LOCK, pValue);
295 }
296
297
298
299
300
301
302
303 private void setValueCreationDate(final OceanusDate pValue) throws OceanusException {
304 getValues().setValue(PrometheusDataResource.CONTROLKEY_CREATION, pValue);
305 }
306
307 @Override
308 public PrometheusControlKey getBase() {
309 return (PrometheusControlKey) super.getBase();
310 }
311
312 @Override
313 public PrometheusControlKeyList getList() {
314 return (PrometheusControlKeyList) super.getList();
315 }
316
317
318
319
320
321
322 PrometheusDataKeySet getNextDataKeySet() {
323 return theKeySetCache.getNextDataKeySet();
324 }
325
326 @Override
327 public int compareValues(final PrometheusDataItem pThat) {
328
329 return 0;
330 }
331
332
333
334
335
336
337
338 private void allocateControlKeySets(final PrometheusDataSet pData) throws OceanusException {
339
340 final PrometheusControlKeySetList mySets = pData.getControlKeySets();
341 setNewVersion();
342
343
344 final int myNumKeySets = pData.getNumActiveKeySets();
345 for (int i = 0; i < myNumKeySets; i++) {
346
347 final PrometheusControlKeySet mySet = new PrometheusControlKeySet(mySets, this);
348 mySet.setNewVersion();
349 mySets.add(mySet);
350
351
352 theKeySetCache.registerControlKeySet(mySet);
353 }
354 }
355
356
357
358
359 void deleteControlSet() {
360
361 theKeySetCache.deleteControlKeySets();
362
363
364 setDeleted(true);
365 }
366
367
368
369
370
371
372
373 void updateFactoryLock(final String pSource) throws OceanusException {
374
375 final PrometheusDataSet myData = getDataSet();
376 final PrometheusSecurityPasswordManager myPasswordMgr = myData.getPasswordMgr();
377
378
379 final GordianFactoryLock myLock = myPasswordMgr.newFactoryLock(getSecurityFactory(), pSource);
380
381
382 pushHistory();
383
384
385 setValueFactoryLock(myLock);
386 setValueFactoryLockBytes(myLock.getLockBytes());
387 myData.setVersion(myData.getVersion() + 1);
388
389
390 checkForHistory();
391 }
392
393
394
395
396
397
398 void registerControlKeySet(final PrometheusControlKeySet pKeySet) {
399
400 theKeySetCache.registerControlKeySet(pKeySet);
401 }
402
403
404
405
406 public static class PrometheusControlKeyList
407 extends PrometheusDataList<PrometheusControlKey> {
408
409
410
411 private static final MetisFieldSet<PrometheusControlKeyList> FIELD_DEFS = MetisFieldSet.newFieldSet(PrometheusControlKeyList.class);
412
413
414
415
416
417
418 protected PrometheusControlKeyList(final PrometheusDataSet pData) {
419 this(pData, PrometheusListStyle.CORE);
420 }
421
422
423
424
425
426
427
428 protected PrometheusControlKeyList(final PrometheusDataSet pData,
429 final PrometheusListStyle pStyle) {
430 super(PrometheusControlKey.class, pData, PrometheusCryptographyDataType.CONTROLKEY, pStyle);
431 }
432
433
434
435
436
437
438 private PrometheusControlKeyList(final PrometheusControlKeyList pSource) {
439 super(pSource);
440 }
441
442 @Override
443 public MetisFieldSet<PrometheusControlKeyList> getDataFieldSet() {
444 return FIELD_DEFS;
445 }
446
447 @Override
448 public String listName() {
449 return LIST_NAME;
450 }
451
452 @Override
453 public MetisFieldSet<PrometheusControlKey> getItemFields() {
454 return PrometheusControlKey.FIELD_DEFS;
455 }
456
457 @Override
458 public boolean includeDataXML() {
459 return false;
460 }
461
462 @Override
463 protected PrometheusControlKeyList getEmptyList(final PrometheusListStyle pStyle) {
464 final PrometheusControlKeyList myList = new PrometheusControlKeyList(this);
465 myList.setStyle(pStyle);
466 return myList;
467 }
468
469 @Override
470 public PrometheusControlKeyList deriveList(final PrometheusListStyle pStyle) throws OceanusException {
471 return (PrometheusControlKeyList) super.deriveList(pStyle);
472 }
473
474 @Override
475 public PrometheusControlKeyList deriveDifferences(final PrometheusDataSet pDataSet,
476 final PrometheusDataList<?> pOld) {
477 return (PrometheusControlKeyList) super.deriveDifferences(pDataSet, pOld);
478 }
479
480 @Override
481 public PrometheusControlKey addCopyItem(final PrometheusDataItem pItem) {
482
483 if (!(pItem instanceof PrometheusControlKey)) {
484 return null;
485 }
486
487
488 final PrometheusControlKey myKey = new PrometheusControlKey(this, (PrometheusControlKey) pItem);
489 add(myKey);
490 return myKey;
491 }
492
493 @Override
494 public PrometheusControlKey addNewItem() {
495 throw new UnsupportedOperationException();
496 }
497
498 @Override
499 public PrometheusControlKey addValuesItem(final PrometheusDataValues pValues) throws OceanusException {
500
501 final PrometheusControlKey myKey = new PrometheusControlKey(this, pValues);
502
503
504 if (!isIdUnique(myKey.getIndexedId())) {
505 myKey.addError(ERROR_DUPLICATE, MetisDataResource.DATA_ID);
506 throw new PrometheusDataException(myKey, ERROR_VALIDATION);
507 }
508
509
510 add(myKey);
511
512
513 return myKey;
514 }
515
516
517
518
519
520
521
522 public PrometheusControlKey createNewKeySet() throws OceanusException {
523
524 final PrometheusControlKey myKey = new PrometheusControlKey(this);
525
526
527 add(myKey);
528 return myKey;
529 }
530
531
532
533
534
535
536
537
538 public PrometheusControlKey cloneItem(final PrometheusControlKey pSource) throws OceanusException {
539
540 final PrometheusControlKey myKey = new PrometheusControlKey(pSource);
541
542
543 add(myKey);
544 return myKey;
545 }
546
547
548
549
550
551
552
553 protected void initialiseSecurity(final PrometheusDataSet pDatabase) throws OceanusException {
554
555 final PrometheusDataSet myData = getDataSet();
556 final PrometheusControlKey myDatabaseKey = pDatabase.getControlKey();
557 final PrometheusControlKey myKey;
558
559
560 if (myDatabaseKey != null) {
561
562 myKey = cloneControlKey(myDatabaseKey);
563
564
565 } else {
566
567 myKey = createNewKeySet();
568 }
569
570
571 myData.getControl().setControlKey(myKey);
572 }
573
574
575
576
577 protected void purgeOldControlKeys() {
578
579 final PrometheusDataSet myData = getDataSet();
580 final PrometheusControlKey myKey = myData.getControlKey();
581
582
583 final Iterator<PrometheusControlKey> myIterator = iterator();
584 while (myIterator.hasNext()) {
585 final PrometheusControlKey myCurr = myIterator.next();
586
587
588 if (!myKey.equals(myCurr)) {
589 myCurr.deleteControlSet();
590 }
591 }
592 }
593
594
595
596
597
598
599
600
601 private PrometheusControlKey cloneControlKey(final PrometheusControlKey pControlKey) throws OceanusException {
602
603 final PrometheusDataValues myValues = new PrometheusDataValues(OBJECT_NAME);
604 myValues.addValue(MetisDataResource.DATA_ID, pControlKey.getIndexedId());
605 myValues.addValue(PrometheusDataResource.CONTROLKEY_LOCKBYTES, pControlKey.getLockBytes());
606 myValues.addValue(PrometheusDataResource.CONTROLKEY_CREATION, pControlKey.getCreationDate());
607 myValues.addValue(PrometheusDataResource.CONTROLKEY_LOCK, pControlKey.getFactoryLock());
608
609
610 final PrometheusControlKey myControl = addValuesItem(myValues);
611
612
613 final PrometheusDataSet myData = getDataSet();
614 final PrometheusControlKeySetList myKeySets = myData.getControlKeySets();
615
616
617 final ControlKeySetCache mySource = pControlKey.getControlKeySets();
618 myControl.theKeySetCache = mySource.cloneControlKeySetCache(myControl, myKeySets);
619
620
621 return myControl;
622 }
623
624 @Override
625 public void postProcessOnLoad() throws OceanusException {
626
627 reSort();
628 }
629
630 @Override
631 protected PrometheusDataMapItem allocateDataMap() {
632
633 throw new UnsupportedOperationException();
634 }
635 }
636
637
638
639
640 private static final class ControlKeySetCache
641 implements MetisFieldItem, MetisDataList<PrometheusControlKeySet> {
642
643
644
645 private static final MetisFieldSet<ControlKeySetCache> FIELD_DEFS = MetisFieldSet.newFieldSet(ControlKeySetCache.class);
646
647
648
649
650 static {
651 FIELD_DEFS.declareLocalField(MetisDataResource.LIST_SIZE, ControlKeySetCache::size);
652 }
653
654
655
656
657 private final List<PrometheusControlKeySet> theList;
658
659
660
661
662 private Iterator<PrometheusControlKeySet> theIterator;
663
664
665
666
667 ControlKeySetCache() {
668 theList = new ArrayList<>();
669 }
670
671 @Override
672 public MetisFieldSet<ControlKeySetCache> getDataFieldSet() {
673 return FIELD_DEFS;
674 }
675
676 @Override
677 public List<PrometheusControlKeySet> getUnderlyingList() {
678 return theList;
679 }
680
681 @Override
682 public String formatObject(final OceanusDataFormatter pFormatter) {
683 return getDataFieldSet().getName();
684 }
685
686
687
688
689
690
691 private void registerControlKeySet(final PrometheusControlKeySet pKeySet) {
692
693 if (!theList.contains(pKeySet)) {
694
695 theList.add(pKeySet);
696
697
698 if (theIterator != null) {
699 theIterator = iterator();
700 }
701 }
702 }
703
704
705
706
707
708
709 private PrometheusDataKeySet getNextDataKeySet() {
710
711 if (isEmpty()) {
712 return null;
713 }
714
715
716 if (theIterator == null
717 || !theIterator.hasNext()) {
718 theIterator = iterator();
719 }
720
721
722 return theIterator.next().getNextDataKeySet();
723 }
724
725
726
727
728 private void deleteControlKeySets() {
729
730 final Iterator<PrometheusControlKeySet> myIterator = iterator();
731 while (myIterator.hasNext()) {
732 final PrometheusControlKeySet mySet = myIterator.next();
733
734
735 mySet.deleteControlKeySet();
736 }
737 }
738
739
740
741
742
743
744
745
746
747 private ControlKeySetCache cloneControlKeySetCache(final PrometheusControlKey pControlKey,
748 final PrometheusControlKeySetList pKeySets) throws OceanusException {
749
750 final ControlKeySetCache myCache = new ControlKeySetCache();
751
752
753 final Iterator<PrometheusControlKeySet> myIterator = iterator();
754 while (myIterator.hasNext()) {
755 final PrometheusControlKeySet mySet = myIterator.next();
756
757
758 final PrometheusControlKeySet myNewSet = pKeySets.cloneControlKeySet(pControlKey, mySet);
759 myCache.registerControlKeySet(myNewSet);
760 }
761
762
763 return myCache;
764 }
765 }
766 }