@striae-org/striae 4.0.3 → 4.2.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.
Files changed (118) hide show
  1. package/.env.example +8 -0
  2. package/app/components/actions/case-export/core-export.ts +14 -8
  3. package/app/components/actions/case-export/data-processing.ts +1 -0
  4. package/app/components/actions/case-export/download-handlers.ts +7 -0
  5. package/app/components/actions/case-export/metadata-helpers.ts +2 -1
  6. package/app/components/actions/case-import/confirmation-import.ts +12 -2
  7. package/app/components/actions/case-import/orchestrator.ts +78 -32
  8. package/app/components/actions/case-import/storage-operations.ts +97 -8
  9. package/app/components/actions/case-import/zip-processing.ts +159 -86
  10. package/app/components/actions/case-manage.ts +430 -8
  11. package/app/components/actions/confirm-export.ts +13 -4
  12. package/app/components/actions/generate-pdf.ts +10 -2
  13. package/app/components/actions/image-manage.ts +77 -44
  14. package/app/components/audit/user-audit-viewer.tsx +137 -945
  15. package/app/components/audit/user-audit.module.css +41 -0
  16. package/app/components/audit/viewer/audit-activity-summary.tsx +52 -0
  17. package/app/components/audit/viewer/audit-entries-list.tsx +207 -0
  18. package/app/components/audit/viewer/audit-filters-panel.tsx +307 -0
  19. package/app/components/audit/viewer/audit-user-info-card.tsx +44 -0
  20. package/app/components/audit/viewer/audit-viewer-header.tsx +55 -0
  21. package/app/components/audit/viewer/audit-viewer-utils.ts +123 -0
  22. package/app/components/audit/viewer/types.ts +1 -0
  23. package/app/components/audit/viewer/use-audit-viewer-data.ts +186 -0
  24. package/app/components/audit/viewer/use-audit-viewer-export.ts +176 -0
  25. package/app/components/audit/viewer/use-audit-viewer-filters.ts +141 -0
  26. package/app/components/auth/mfa-enrollment.module.css +13 -5
  27. package/app/components/auth/mfa-verification.module.css +13 -5
  28. package/app/components/canvas/box-annotations/box-annotations.module.css +22 -18
  29. package/app/components/canvas/box-annotations/box-annotations.tsx +15 -0
  30. package/app/components/canvas/canvas.module.css +64 -54
  31. package/app/components/canvas/canvas.tsx +17 -16
  32. package/app/components/canvas/confirmation/confirmation.module.css +1 -0
  33. package/app/components/canvas/confirmation/confirmation.tsx +17 -47
  34. package/app/components/navbar/case-modals/archive-case-modal.module.css +110 -0
  35. package/app/components/navbar/case-modals/archive-case-modal.tsx +129 -0
  36. package/app/components/navbar/case-modals/open-case-modal.module.css +81 -0
  37. package/app/components/navbar/case-modals/open-case-modal.tsx +120 -0
  38. package/app/components/navbar/case-modals/rename-case-modal.module.css +81 -0
  39. package/app/components/navbar/case-modals/rename-case-modal.tsx +107 -0
  40. package/app/components/navbar/navbar.module.css +447 -0
  41. package/app/components/navbar/navbar.tsx +377 -0
  42. package/app/components/public-signing-key-modal/public-signing-key-modal.module.css +2 -0
  43. package/app/components/public-signing-key-modal/public-signing-key-modal.tsx +21 -51
  44. package/app/components/sidebar/case-export/case-export.module.css +1 -0
  45. package/app/components/sidebar/case-export/case-export.tsx +14 -77
  46. package/app/components/sidebar/case-import/case-import.module.css +25 -0
  47. package/app/components/sidebar/case-import/case-import.tsx +64 -40
  48. package/app/components/sidebar/case-import/components/CasePreviewSection.tsx +20 -1
  49. package/app/components/sidebar/case-import/components/ConfirmationDialog.tsx +15 -0
  50. package/app/components/sidebar/cases/case-sidebar.tsx +25 -519
  51. package/app/components/sidebar/cases/cases-modal.module.css +45 -9
  52. package/app/components/sidebar/cases/cases-modal.tsx +16 -16
  53. package/app/components/sidebar/cases/cases.module.css +62 -21
  54. package/app/components/sidebar/files/files-modal.module.css +46 -10
  55. package/app/components/sidebar/files/files-modal.tsx +22 -23
  56. package/app/components/sidebar/notes/notes-editor-modal.module.css +49 -0
  57. package/app/components/sidebar/notes/notes-editor-modal.tsx +66 -0
  58. package/app/components/sidebar/notes/notes-modal.tsx +18 -17
  59. package/app/components/sidebar/notes/notes-sidebar.tsx +199 -113
  60. package/app/components/sidebar/notes/notes.module.css +155 -0
  61. package/app/components/sidebar/sidebar-container.tsx +15 -28
  62. package/app/components/sidebar/sidebar.module.css +7 -71
  63. package/app/components/sidebar/sidebar.tsx +24 -125
  64. package/app/components/sidebar/upload/image-upload-zone.module.css +13 -13
  65. package/app/components/toast/toast.module.css +2 -1
  66. package/app/components/toast/toast.tsx +16 -11
  67. package/app/components/user/delete-account.tsx +10 -31
  68. package/app/components/user/inactivity-warning.module.css +9 -6
  69. package/app/components/user/inactivity-warning.tsx +15 -2
  70. package/app/components/user/manage-profile.module.css +2 -0
  71. package/app/components/user/manage-profile.tsx +108 -40
  72. package/app/hooks/useOverlayDismiss.ts +116 -0
  73. package/app/routes/auth/login.example.tsx +19 -8
  74. package/app/routes/auth/login.tsx +785 -774
  75. package/app/routes/auth/passwordReset.module.css +23 -13
  76. package/app/routes/striae/striae.module.css +10 -3
  77. package/app/routes/striae/striae.tsx +477 -31
  78. package/app/routes.ts +7 -0
  79. package/app/services/audit/audit-export-csv.ts +2 -0
  80. package/app/services/audit/audit.service.ts +202 -32
  81. package/app/services/audit/builders/audit-entry-builder.ts +2 -1
  82. package/app/services/audit/builders/audit-event-builders-case-file.ts +43 -0
  83. package/app/services/audit/builders/audit-event-builders-user-security.ts +4 -2
  84. package/app/services/audit/builders/audit-event-builders-workflow.ts +8 -0
  85. package/app/services/audit/builders/index.ts +1 -0
  86. package/app/types/audit.ts +5 -2
  87. package/app/types/case.ts +29 -0
  88. package/app/types/import.ts +3 -0
  89. package/app/types/user.ts +1 -0
  90. package/app/utils/data/permissions.ts +17 -1
  91. package/app/utils/forensics/audit-export-signature.ts +5 -1
  92. package/app/utils/forensics/confirmation-signature.ts +3 -0
  93. package/app/utils/forensics/export-verification.ts +497 -22
  94. package/functions/api/pdf/[[path]].ts +32 -1
  95. package/load-context.ts +9 -0
  96. package/package.json +6 -2
  97. package/primershear.emails.example +6 -0
  98. package/scripts/deploy-pages-secrets.sh +6 -0
  99. package/scripts/deploy-primershear-emails.sh +167 -0
  100. package/worker-configuration.d.ts +7493 -7491
  101. package/workers/audit-worker/worker-configuration.d.ts +7448 -11323
  102. package/workers/audit-worker/wrangler.jsonc.example +1 -1
  103. package/workers/data-worker/worker-configuration.d.ts +7448 -11323
  104. package/workers/data-worker/wrangler.jsonc.example +1 -1
  105. package/workers/image-worker/worker-configuration.d.ts +7447 -11322
  106. package/workers/image-worker/wrangler.jsonc.example +1 -1
  107. package/workers/keys-worker/worker-configuration.d.ts +7447 -11322
  108. package/workers/keys-worker/wrangler.jsonc.example +1 -1
  109. package/workers/pdf-worker/src/formats/format-striae.ts +8 -7
  110. package/workers/pdf-worker/src/pdf-worker.example.ts +3 -0
  111. package/workers/pdf-worker/src/report-types.ts +3 -0
  112. package/workers/pdf-worker/worker-configuration.d.ts +7448 -11323
  113. package/workers/pdf-worker/wrangler.jsonc.example +1 -1
  114. package/workers/user-worker/src/user-worker.example.ts +6 -1
  115. package/workers/user-worker/worker-configuration.d.ts +7448 -11323
  116. package/workers/user-worker/wrangler.jsonc.example +1 -1
  117. package/wrangler.toml.example +1 -1
  118. package/public/.well-known/keybase.txt +0 -56
package/app/types/case.ts CHANGED
@@ -1,14 +1,30 @@
1
1
  import { type FileData } from './file';
2
2
  import { type AnnotationData, type ConfirmationData } from './annotations';
3
+ import { type ValidationAuditEntry } from './audit';
3
4
 
4
5
  // Case-related types and interfaces
5
6
 
6
7
  export type CaseActionType = 'loaded' | 'created' | 'deleted' | null;
7
8
 
9
+ export interface BundledAuditTrailData {
10
+ source: 'archive-bundle';
11
+ importedAt: string;
12
+ exportTimestamp?: string;
13
+ totalEntries?: number;
14
+ entries: ValidationAuditEntry[];
15
+ }
16
+
8
17
  export interface CaseData {
9
18
  createdAt: string;
10
19
  caseNumber: string;
11
20
  files: FileData[];
21
+ isReadOnly?: boolean;
22
+ archived?: boolean;
23
+ archivedAt?: string;
24
+ archivedBy?: string;
25
+ archivedByDisplay?: string;
26
+ archiveReason?: string;
27
+ bundledAuditTrail?: BundledAuditTrailData;
12
28
  }
13
29
 
14
30
  export interface ReadOnlyCaseData extends CaseData {
@@ -23,11 +39,17 @@ export interface CaseExportData {
23
39
  metadata: {
24
40
  caseNumber: string;
25
41
  caseCreatedDate: string;
42
+ archived?: boolean;
43
+ archivedAt?: string;
44
+ archivedBy?: string;
45
+ archivedByDisplay?: string;
46
+ archiveReason?: string;
26
47
  exportDate: string;
27
48
  exportedBy: string | null;
28
49
  exportedByUid: string;
29
50
  exportedByName: string;
30
51
  exportedByCompany: string;
52
+ exportedByBadgeId?: string;
31
53
  striaeExportSchemaVersion: string;
32
54
  totalFiles: number;
33
55
  };
@@ -56,6 +78,7 @@ export interface AllCasesExportData {
56
78
  exportedByUid: string;
57
79
  exportedByName: string;
58
80
  exportedByCompany: string;
81
+ exportedByBadgeId?: string;
59
82
  striaeExportSchemaVersion: string;
60
83
  totalCases: number;
61
84
  totalFiles: number;
@@ -84,7 +107,13 @@ export interface CaseDataWithConfirmations {
84
107
  caseNumber: string;
85
108
  files: FileData[];
86
109
  isReadOnly?: boolean;
110
+ archived?: boolean;
111
+ archivedAt?: string;
112
+ archivedBy?: string;
113
+ archivedByDisplay?: string;
114
+ archiveReason?: string;
87
115
  importedAt?: string;
88
116
  originalImageIds?: { [originalId: string]: string };
89
117
  confirmations?: CaseConfirmations;
118
+ bundledAuditTrail?: BundledAuditTrailData;
90
119
  }
@@ -51,6 +51,7 @@ export interface ConfirmationImportData {
51
51
  exportedByUid: string;
52
52
  exportedByName: string;
53
53
  exportedByCompany: string;
54
+ exportedByBadgeId?: string;
54
55
  totalConfirmations: number;
55
56
  version: string;
56
57
  hash: string;
@@ -79,9 +80,11 @@ export interface ConfirmationImportData {
79
80
 
80
81
  export interface CaseImportPreview {
81
82
  caseNumber: string;
83
+ archived?: boolean;
82
84
  exportedBy: string | null;
83
85
  exportedByName: string | null;
84
86
  exportedByCompany: string | null;
87
+ exportedByBadgeId?: string | null;
85
88
  exportDate: string;
86
89
  totalFiles: number;
87
90
  caseCreatedDate?: string;
package/app/types/user.ts CHANGED
@@ -8,6 +8,7 @@ export interface UserData {
8
8
  firstName: string;
9
9
  lastName: string;
10
10
  company: string;
11
+ badgeId?: string;
11
12
  permitted: boolean;
12
13
  cases: Array<{
13
14
  caseNumber: string;
@@ -1,7 +1,7 @@
1
1
  import type { User } from 'firebase/auth';
2
2
  import type { UserData, ExtendedUserData, UserLimits, ReadOnlyCaseMetadata } from '~/types';
3
3
  import paths from '~/config/config.json';
4
- import { fetchUserApi } from '../api';
4
+ import { fetchDataApi, fetchUserApi } from '../api';
5
5
 
6
6
  const MAX_CASES_REVIEW = paths.max_cases_review;
7
7
  const MAX_FILES_PER_CASE_REVIEW = paths.max_files_per_case_review;
@@ -110,6 +110,7 @@ export const createUser = async (
110
110
  firstName,
111
111
  lastName,
112
112
  company,
113
+ badgeId: '',
113
114
  permitted,
114
115
  cases: [],
115
116
  readOnlyCases: [],
@@ -402,6 +403,21 @@ export const canModifyCase = async (user: User, caseNumber: string): Promise<Per
402
403
  return { allowed: false, reason: 'User data not found' };
403
404
  }
404
405
 
406
+ const archiveCheckResponse = await fetchDataApi(
407
+ user,
408
+ `/${encodeURIComponent(user.uid)}/${encodeURIComponent(caseNumber)}/data.json`,
409
+ {
410
+ method: 'GET'
411
+ }
412
+ );
413
+
414
+ if (archiveCheckResponse.ok) {
415
+ const caseData = await archiveCheckResponse.json() as { archived?: boolean };
416
+ if (caseData.archived) {
417
+ return { allowed: false, reason: 'Archived cases are immutable and read-only' };
418
+ }
419
+ }
420
+
405
421
  // Check if user owns the case (regular cases)
406
422
  if (userData.cases && userData.cases.some(c => c.caseNumber === caseNumber)) {
407
423
  // For owned cases, user must be permitted
@@ -83,7 +83,8 @@ export function createAuditExportSigningPayload(payload: AuditExportSigningPaylo
83
83
 
84
84
  export async function verifyAuditExportSignature(
85
85
  payload: Partial<AuditExportSigningPayload>,
86
- signature?: ForensicManifestSignature
86
+ signature?: ForensicManifestSignature,
87
+ verificationPublicKeyPem?: string
87
88
  ): Promise<ManifestSignatureVerificationResult> {
88
89
  if (!signature) {
89
90
  return {
@@ -112,6 +113,9 @@ export async function verifyAuditExportSignature(
112
113
  noVerificationKeyPrefix: 'No verification key configured for key ID',
113
114
  invalidPublicKeyError: 'Audit export signature verification failed: invalid public key',
114
115
  verificationFailedError: 'Audit export signature verification failed'
116
+ },
117
+ {
118
+ verificationPublicKeyPem
115
119
  }
116
120
  );
117
121
  }
@@ -134,6 +134,9 @@ export function createConfirmationSigningPayload(
134
134
  exportedByUid: confirmationData.metadata.exportedByUid,
135
135
  exportedByName: confirmationData.metadata.exportedByName,
136
136
  exportedByCompany: confirmationData.metadata.exportedByCompany,
137
+ ...(confirmationData.metadata.exportedByBadgeId
138
+ ? { exportedByBadgeId: confirmationData.metadata.exportedByBadgeId }
139
+ : {}),
137
140
  totalConfirmations: confirmationData.metadata.totalConfirmations,
138
141
  version: confirmationData.metadata.version,
139
142
  hash: confirmationData.metadata.hash.toUpperCase(),