@striae-org/striae 3.0.4

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 (223) hide show
  1. package/.env.example +100 -0
  2. package/LICENSE +190 -0
  3. package/NOTICE +18 -0
  4. package/README.md +133 -0
  5. package/app/components/actions/case-export/core-export.ts +328 -0
  6. package/app/components/actions/case-export/data-processing.ts +167 -0
  7. package/app/components/actions/case-export/download-handlers.ts +900 -0
  8. package/app/components/actions/case-export/index.ts +41 -0
  9. package/app/components/actions/case-export/metadata-helpers.ts +107 -0
  10. package/app/components/actions/case-export/types-constants.ts +56 -0
  11. package/app/components/actions/case-export/validation-utils.ts +25 -0
  12. package/app/components/actions/case-export.ts +4 -0
  13. package/app/components/actions/case-import/annotation-import.ts +35 -0
  14. package/app/components/actions/case-import/confirmation-import.ts +363 -0
  15. package/app/components/actions/case-import/image-operations.ts +61 -0
  16. package/app/components/actions/case-import/index.ts +39 -0
  17. package/app/components/actions/case-import/orchestrator.ts +420 -0
  18. package/app/components/actions/case-import/storage-operations.ts +270 -0
  19. package/app/components/actions/case-import/validation.ts +189 -0
  20. package/app/components/actions/case-import/zip-processing.ts +413 -0
  21. package/app/components/actions/case-manage.ts +524 -0
  22. package/app/components/actions/case-review.ts +4 -0
  23. package/app/components/actions/confirm-export.ts +351 -0
  24. package/app/components/actions/generate-pdf.ts +210 -0
  25. package/app/components/actions/image-manage.ts +385 -0
  26. package/app/components/actions/notes-manage.ts +33 -0
  27. package/app/components/actions/signout.module.css +15 -0
  28. package/app/components/actions/signout.tsx +50 -0
  29. package/app/components/audit/user-audit-viewer.tsx +975 -0
  30. package/app/components/audit/user-audit.module.css +568 -0
  31. package/app/components/auth/auth-provider.tsx +78 -0
  32. package/app/components/auth/mfa-enrollment.module.css +268 -0
  33. package/app/components/auth/mfa-enrollment.tsx +398 -0
  34. package/app/components/auth/mfa-verification.module.css +251 -0
  35. package/app/components/auth/mfa-verification.tsx +295 -0
  36. package/app/components/button/button.module.css +63 -0
  37. package/app/components/button/button.tsx +46 -0
  38. package/app/components/canvas/box-annotations/box-annotations.module.css +170 -0
  39. package/app/components/canvas/box-annotations/box-annotations.tsx +634 -0
  40. package/app/components/canvas/canvas.module.css +314 -0
  41. package/app/components/canvas/canvas.tsx +449 -0
  42. package/app/components/canvas/confirmation/confirmation.module.css +187 -0
  43. package/app/components/canvas/confirmation/confirmation.tsx +214 -0
  44. package/app/components/colors/colors.module.css +59 -0
  45. package/app/components/colors/colors.tsx +68 -0
  46. package/app/components/form/base-form.tsx +21 -0
  47. package/app/components/form/form-button.tsx +28 -0
  48. package/app/components/form/form-field.tsx +53 -0
  49. package/app/components/form/form-message.tsx +17 -0
  50. package/app/components/form/form-toggle.tsx +23 -0
  51. package/app/components/form/form.module.css +427 -0
  52. package/app/components/form/index.ts +6 -0
  53. package/app/components/icon/icon.module.css +3 -0
  54. package/app/components/icon/icon.tsx +27 -0
  55. package/app/components/icon/icons.svg +102 -0
  56. package/app/components/icon/manifest.json +110 -0
  57. package/app/components/sidebar/case-export/case-export.module.css +386 -0
  58. package/app/components/sidebar/case-export/case-export.tsx +317 -0
  59. package/app/components/sidebar/case-import/case-import.module.css +626 -0
  60. package/app/components/sidebar/case-import/case-import.tsx +404 -0
  61. package/app/components/sidebar/case-import/components/CasePreviewSection.tsx +72 -0
  62. package/app/components/sidebar/case-import/components/ConfirmationDialog.tsx +72 -0
  63. package/app/components/sidebar/case-import/components/ConfirmationPreviewSection.tsx +71 -0
  64. package/app/components/sidebar/case-import/components/ExistingCaseSection.tsx +40 -0
  65. package/app/components/sidebar/case-import/components/FileSelector.tsx +161 -0
  66. package/app/components/sidebar/case-import/components/ProgressSection.tsx +46 -0
  67. package/app/components/sidebar/case-import/hooks/useFilePreview.ts +101 -0
  68. package/app/components/sidebar/case-import/hooks/useImportExecution.ts +152 -0
  69. package/app/components/sidebar/case-import/hooks/useImportState.ts +88 -0
  70. package/app/components/sidebar/case-import/index.ts +18 -0
  71. package/app/components/sidebar/case-import/utils/file-validation.ts +43 -0
  72. package/app/components/sidebar/cases/case-sidebar.tsx +827 -0
  73. package/app/components/sidebar/cases/cases-modal.module.css +166 -0
  74. package/app/components/sidebar/cases/cases-modal.tsx +201 -0
  75. package/app/components/sidebar/cases/cases.module.css +713 -0
  76. package/app/components/sidebar/files/files-modal.module.css +209 -0
  77. package/app/components/sidebar/files/files-modal.tsx +239 -0
  78. package/app/components/sidebar/hash/hash-utility.module.css +366 -0
  79. package/app/components/sidebar/hash/hash-utility.tsx +982 -0
  80. package/app/components/sidebar/notes/notes-modal.tsx +51 -0
  81. package/app/components/sidebar/notes/notes-sidebar.tsx +491 -0
  82. package/app/components/sidebar/notes/notes.module.css +360 -0
  83. package/app/components/sidebar/sidebar-container.tsx +149 -0
  84. package/app/components/sidebar/sidebar.module.css +321 -0
  85. package/app/components/sidebar/sidebar.tsx +215 -0
  86. package/app/components/sidebar/upload/image-upload-zone.module.css +123 -0
  87. package/app/components/sidebar/upload/image-upload-zone.tsx +330 -0
  88. package/app/components/theme-provider/theme-provider.tsx +131 -0
  89. package/app/components/theme-provider/theme.ts +155 -0
  90. package/app/components/toast/toast.module.css +137 -0
  91. package/app/components/toast/toast.tsx +56 -0
  92. package/app/components/toolbar/toolbar-color-selector.module.css +171 -0
  93. package/app/components/toolbar/toolbar-color-selector.tsx +129 -0
  94. package/app/components/toolbar/toolbar.module.css +42 -0
  95. package/app/components/toolbar/toolbar.tsx +167 -0
  96. package/app/components/user/delete-account.module.css +274 -0
  97. package/app/components/user/delete-account.tsx +471 -0
  98. package/app/components/user/inactivity-warning.module.css +145 -0
  99. package/app/components/user/inactivity-warning.tsx +84 -0
  100. package/app/components/user/manage-profile.module.css +190 -0
  101. package/app/components/user/manage-profile.tsx +253 -0
  102. package/app/components/user/mfa-phone-update.tsx +739 -0
  103. package/app/config-example/admin-service.json +13 -0
  104. package/app/config-example/config.json +17 -0
  105. package/app/config-example/firebase.ts +21 -0
  106. package/app/config-example/inactivity.ts +13 -0
  107. package/app/config-example/meta-config.json +6 -0
  108. package/app/contexts/auth.context.ts +12 -0
  109. package/app/entry.client.tsx +12 -0
  110. package/app/entry.server.tsx +44 -0
  111. package/app/hooks/useInactivityTimeout.ts +110 -0
  112. package/app/root.tsx +170 -0
  113. package/app/routes/_index.tsx +16 -0
  114. package/app/routes/auth/emailActionHandler.module.css +232 -0
  115. package/app/routes/auth/emailActionHandler.tsx +405 -0
  116. package/app/routes/auth/emailVerification.tsx +120 -0
  117. package/app/routes/auth/login.module.css +523 -0
  118. package/app/routes/auth/login.tsx +654 -0
  119. package/app/routes/auth/passwordReset.module.css +274 -0
  120. package/app/routes/auth/passwordReset.tsx +154 -0
  121. package/app/routes/auth/route.ts +16 -0
  122. package/app/routes/mobile-prevented/mobilePrevented.module.css +47 -0
  123. package/app/routes/mobile-prevented/mobilePrevented.tsx +26 -0
  124. package/app/routes/mobile-prevented/route.ts +14 -0
  125. package/app/routes/striae/striae.module.css +30 -0
  126. package/app/routes/striae/striae.tsx +417 -0
  127. package/app/services/audit-export.service.ts +755 -0
  128. package/app/services/audit.service.ts +1454 -0
  129. package/app/services/firebase-errors.ts +106 -0
  130. package/app/services/firebase.ts +15 -0
  131. package/app/styles/legal-pages.module.css +113 -0
  132. package/app/styles/root.module.css +146 -0
  133. package/app/tailwind.css +225 -0
  134. package/app/types/annotations.ts +45 -0
  135. package/app/types/audit.ts +301 -0
  136. package/app/types/case.ts +90 -0
  137. package/app/types/export.ts +8 -0
  138. package/app/types/file.ts +30 -0
  139. package/app/types/import.ts +107 -0
  140. package/app/types/index.ts +24 -0
  141. package/app/types/user.ts +38 -0
  142. package/app/utils/SHA256.ts +461 -0
  143. package/app/utils/annotation-timestamp.ts +25 -0
  144. package/app/utils/audit-export-signature.ts +117 -0
  145. package/app/utils/auth-action-settings.ts +48 -0
  146. package/app/utils/auth.ts +34 -0
  147. package/app/utils/batch-operations.ts +135 -0
  148. package/app/utils/confirmation-signature.ts +193 -0
  149. package/app/utils/data-operations.ts +871 -0
  150. package/app/utils/device-detection.ts +5 -0
  151. package/app/utils/html-sanitizer.ts +80 -0
  152. package/app/utils/id-generator.ts +36 -0
  153. package/app/utils/meta.ts +48 -0
  154. package/app/utils/mfa-phone.ts +97 -0
  155. package/app/utils/mfa.ts +79 -0
  156. package/app/utils/password-policy.ts +28 -0
  157. package/app/utils/permissions.ts +562 -0
  158. package/app/utils/signature-utils.ts +160 -0
  159. package/app/utils/style.ts +83 -0
  160. package/app/utils/version.ts +5 -0
  161. package/firebase.json +11 -0
  162. package/functions/[[path]].ts +10 -0
  163. package/package.json +138 -0
  164. package/postcss.config.js +6 -0
  165. package/public/.well-known/publickey.info@striae.org.asc +17 -0
  166. package/public/.well-known/security.txt +7 -0
  167. package/public/_headers +28 -0
  168. package/public/_routes.json +13 -0
  169. package/public/assets/striae.jpg +0 -0
  170. package/public/clear.jpg +0 -0
  171. package/public/favicon.ico +0 -0
  172. package/public/favicon.svg +9 -0
  173. package/public/icon-256.png +0 -0
  174. package/public/icon-512.png +0 -0
  175. package/public/logo-dark.png +0 -0
  176. package/public/manifest.json +25 -0
  177. package/public/oin-badge.png +0 -0
  178. package/public/shortcut.png +0 -0
  179. package/public/social-image.png +0 -0
  180. package/public/striae-ascii.txt +10 -0
  181. package/scripts/deploy-all.sh +100 -0
  182. package/scripts/deploy-config.sh +940 -0
  183. package/scripts/deploy-pages.sh +34 -0
  184. package/scripts/deploy-worker-secrets.sh +215 -0
  185. package/scripts/dev.cjs +23 -0
  186. package/scripts/install-workers.sh +88 -0
  187. package/scripts/run-eslint.cjs +35 -0
  188. package/scripts/update-compatibility-dates.cjs +124 -0
  189. package/scripts/update-markdown-versions.cjs +43 -0
  190. package/tailwind.config.ts +22 -0
  191. package/tsconfig.json +33 -0
  192. package/vite.config.ts +35 -0
  193. package/worker-configuration.d.ts +7490 -0
  194. package/workers/audit-worker/package.json +17 -0
  195. package/workers/audit-worker/src/audit-worker.example.ts +195 -0
  196. package/workers/audit-worker/worker-configuration.d.ts +7448 -0
  197. package/workers/audit-worker/wrangler.jsonc.example +29 -0
  198. package/workers/data-worker/package.json +17 -0
  199. package/workers/data-worker/src/data-worker.example.ts +267 -0
  200. package/workers/data-worker/src/signature-utils.ts +79 -0
  201. package/workers/data-worker/src/signing-payload-utils.ts +290 -0
  202. package/workers/data-worker/worker-configuration.d.ts +7448 -0
  203. package/workers/data-worker/wrangler.jsonc.example +30 -0
  204. package/workers/image-worker/package.json +17 -0
  205. package/workers/image-worker/src/image-worker.example.ts +180 -0
  206. package/workers/image-worker/worker-configuration.d.ts +7447 -0
  207. package/workers/image-worker/wrangler.jsonc.example +22 -0
  208. package/workers/keys-worker/package.json +17 -0
  209. package/workers/keys-worker/src/keys.example.ts +66 -0
  210. package/workers/keys-worker/src/keys.ts +66 -0
  211. package/workers/keys-worker/worker-configuration.d.ts +7447 -0
  212. package/workers/keys-worker/wrangler.jsonc.example +22 -0
  213. package/workers/pdf-worker/package.json +17 -0
  214. package/workers/pdf-worker/src/format-striae.ts +534 -0
  215. package/workers/pdf-worker/src/pdf-worker.example.ts +119 -0
  216. package/workers/pdf-worker/src/report-types.ts +69 -0
  217. package/workers/pdf-worker/worker-configuration.d.ts +7448 -0
  218. package/workers/pdf-worker/wrangler.jsonc.example +26 -0
  219. package/workers/user-worker/package.json +17 -0
  220. package/workers/user-worker/src/user-worker.example.ts +636 -0
  221. package/workers/user-worker/worker-configuration.d.ts +7448 -0
  222. package/workers/user-worker/wrangler.jsonc.example +29 -0
  223. package/wrangler.toml.example +8 -0
@@ -0,0 +1,30 @@
1
+ {
2
+ // Required secrets: R2_KEY_SECRET, MANIFEST_SIGNING_PRIVATE_KEY, MANIFEST_SIGNING_KEY_ID
3
+ "name": "DATA_WORKER_NAME",
4
+ "account_id": "ACCOUNT_ID",
5
+ "main": "src/data-worker.ts",
6
+ "compatibility_date": "2026-03-09",
7
+ "compatibility_flags": [
8
+ "nodejs_compat"
9
+ ],
10
+
11
+ "observability": {
12
+ "enabled": true
13
+ },
14
+
15
+ "r2_buckets": [
16
+ {
17
+ "binding": "STRIAE_DATA",
18
+ "bucket_name": "DATA_BUCKET_NAME"
19
+ }
20
+ ],
21
+
22
+ "routes": [
23
+ {
24
+ "pattern": "DATA_WORKER_DOMAIN",
25
+ "custom_domain": true
26
+ }
27
+ ],
28
+
29
+ "placement": { "mode": "smart" }
30
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "image-worker",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "deploy": "wrangler deploy",
7
+ "dev": "wrangler dev",
8
+ "start": "wrangler dev",
9
+ "test": "vitest"
10
+ },
11
+ "devDependencies": {
12
+ "@cloudflare/puppeteer": "^1.0.4",
13
+ "@cloudflare/vitest-pool-workers": "^0.12.9",
14
+ "vitest": "~3.2.0",
15
+ "wrangler": "^4.69.0"
16
+ }
17
+ }
@@ -0,0 +1,180 @@
1
+ interface Env {
2
+ API_TOKEN: string;
3
+ ACCOUNT_ID: string;
4
+ HMAC_KEY: string;
5
+ }
6
+
7
+ interface CloudflareImagesResponse {
8
+ success: boolean;
9
+ errors?: Array<{
10
+ code: number;
11
+ message: string;
12
+ }>;
13
+ messages?: string[];
14
+ result?: {
15
+ id: string;
16
+ filename: string;
17
+ uploaded: string;
18
+ requireSignedURLs: boolean;
19
+ variants: string[];
20
+ };
21
+ }
22
+
23
+ interface ErrorResponse {
24
+ error: string;
25
+ }
26
+
27
+ type APIResponse = CloudflareImagesResponse | ErrorResponse | string;
28
+
29
+ const API_BASE = "https://api.cloudflare.com/client/v4/accounts";
30
+
31
+ /**
32
+ * CORS headers to allow requests from the Striae app
33
+ */
34
+ const corsHeaders: Record<string, string> = {
35
+ 'Access-Control-Allow-Origin': 'PAGES_CUSTOM_DOMAIN',
36
+ 'Access-Control-Allow-Methods': 'GET, POST, DELETE, OPTIONS',
37
+ 'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Custom-Auth-Key',
38
+ 'Content-Type': 'application/json'
39
+ };
40
+
41
+ const createResponse = (data: APIResponse, status: number = 200): Response => new Response(
42
+ typeof data === 'string' ? data : JSON.stringify(data),
43
+ { status, headers: corsHeaders }
44
+ );
45
+
46
+ const hasValidToken = (request: Request, env: Env): boolean => {
47
+ const authHeader = request.headers.get("Authorization");
48
+ const expectedToken = `Bearer ${env.API_TOKEN}`;
49
+ return authHeader === expectedToken;
50
+ };
51
+
52
+ /**
53
+ * Handle image upload requests
54
+ */
55
+ async function handleImageUpload(request: Request, env: Env): Promise<Response> {
56
+ if (!hasValidToken(request, env)) {
57
+ return createResponse({ error: 'Unauthorized' }, 403);
58
+ }
59
+
60
+ const formData = await request.formData();
61
+ const endpoint = `${API_BASE}/${env.ACCOUNT_ID}/images/v1`;
62
+
63
+ // Add requireSignedURLs to form data
64
+ formData.append('requireSignedURLs', 'true');
65
+
66
+ const response = await fetch(endpoint, {
67
+ method: 'POST',
68
+ headers: {
69
+ 'Authorization': `Bearer ${env.API_TOKEN}`,
70
+ },
71
+ body: formData
72
+ });
73
+
74
+ const data: CloudflareImagesResponse = await response.json();
75
+ return createResponse(data, response.status);
76
+ }
77
+
78
+ /**
79
+ * Handle image delete requests
80
+ */
81
+ async function handleImageDelete(request: Request, env: Env): Promise<Response> {
82
+ if (!hasValidToken(request, env)) {
83
+ return createResponse({ error: 'Unauthorized' }, 403);
84
+ }
85
+
86
+ const url = new URL(request.url);
87
+ const imageId = url.pathname.split('/').pop();
88
+
89
+ if (!imageId) {
90
+ return createResponse({ error: 'Image ID is required' }, 400);
91
+ }
92
+
93
+ const endpoint = `${API_BASE}/${env.ACCOUNT_ID}/images/v1/${imageId}`;
94
+ const response = await fetch(endpoint, {
95
+ method: 'DELETE',
96
+ headers: {
97
+ 'Authorization': `Bearer ${env.API_TOKEN}`,
98
+ }
99
+ });
100
+
101
+ const data: CloudflareImagesResponse = await response.json();
102
+ return createResponse(data, response.status);
103
+ }
104
+
105
+ /**
106
+ * Handle Signed URL generation
107
+ */
108
+ const EXPIRATION = 60 * 60; // 1 hour
109
+
110
+ const bufferToHex = (buffer: ArrayBuffer): string =>
111
+ [...new Uint8Array(buffer)].map(x => x.toString(16).padStart(2, '0')).join('');
112
+
113
+ async function generateSignedUrl(url: URL, env: Env): Promise<Response> {
114
+ const encoder = new TextEncoder();
115
+ const secretKeyData = encoder.encode(env.HMAC_KEY);
116
+ const key = await crypto.subtle.importKey(
117
+ 'raw',
118
+ secretKeyData,
119
+ { name: 'HMAC', hash: 'SHA-256' },
120
+ false,
121
+ ['sign']
122
+ );
123
+
124
+ // Add expiration
125
+ const expiry = Math.floor(Date.now() / 1000) + EXPIRATION;
126
+ url.searchParams.set('exp', expiry.toString());
127
+
128
+ const stringToSign = url.pathname + '?' + url.searchParams.toString();
129
+ const mac = await crypto.subtle.sign('HMAC', key, encoder.encode(stringToSign));
130
+ const sig = bufferToHex(mac);
131
+
132
+ // Add signature
133
+ url.searchParams.set('sig', sig);
134
+
135
+ // Return the modified URL with signature and expiration
136
+ return new Response(url.toString(), {
137
+ headers: corsHeaders
138
+ });
139
+ }
140
+
141
+ async function handleImageServing(request: Request, env: Env): Promise<Response> {
142
+ if (!hasValidToken(request, env)) {
143
+ return createResponse({ error: 'Unauthorized' }, 403);
144
+ }
145
+
146
+ const url = new URL(request.url);
147
+ const pathWithoutSlash = url.pathname.slice(1);
148
+ const imageDeliveryURL = new URL(
149
+ pathWithoutSlash.replace('https:/imagedelivery.net', 'https://imagedelivery.net')
150
+ );
151
+
152
+ return generateSignedUrl(imageDeliveryURL, env);
153
+ }
154
+
155
+ /**
156
+ * Main worker functions
157
+ */
158
+ export default {
159
+ async fetch(request: Request, env: Env): Promise<Response> {
160
+ if (request.method === 'OPTIONS') {
161
+ return new Response(null, { headers: corsHeaders });
162
+ }
163
+
164
+ try {
165
+ switch (request.method) {
166
+ case 'POST':
167
+ return handleImageUpload(request, env);
168
+ case 'GET':
169
+ return handleImageServing(request, env);
170
+ case 'DELETE':
171
+ return handleImageDelete(request, env);
172
+ default:
173
+ return createResponse({ error: 'Method not allowed' }, 405);
174
+ }
175
+ } catch (error) {
176
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
177
+ return createResponse({ error: errorMessage }, 500);
178
+ }
179
+ }
180
+ };