verification-layer 0.20.0 → 0.22.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 (180) hide show
  1. package/README.md +251 -615
  2. package/dist/cli.js +542 -0
  3. package/dist/cli.js.map +1 -1
  4. package/dist/marketplace/index.d.ts +8 -0
  5. package/dist/marketplace/index.d.ts.map +1 -0
  6. package/dist/marketplace/index.js +7 -0
  7. package/dist/marketplace/index.js.map +1 -0
  8. package/dist/marketplace/installer.d.ts +62 -0
  9. package/dist/marketplace/installer.d.ts.map +1 -0
  10. package/dist/marketplace/installer.js +254 -0
  11. package/dist/marketplace/installer.js.map +1 -0
  12. package/dist/marketplace/registry.d.ts +52 -0
  13. package/dist/marketplace/registry.d.ts.map +1 -0
  14. package/dist/marketplace/registry.js +759 -0
  15. package/dist/marketplace/registry.js.map +1 -0
  16. package/dist/marketplace/types.d.ts +123 -0
  17. package/dist/marketplace/types.d.ts.map +1 -0
  18. package/dist/marketplace/types.js +6 -0
  19. package/dist/marketplace/types.js.map +1 -0
  20. package/dist/reporters/audit-report.d.ts.map +1 -1
  21. package/dist/reporters/audit-report.js +180 -0
  22. package/dist/reporters/audit-report.js.map +1 -1
  23. package/dist/reporters/index.d.ts.map +1 -1
  24. package/dist/reporters/index.js +2612 -5
  25. package/dist/reporters/index.js.map +1 -1
  26. package/dist/scan.d.ts.map +1 -1
  27. package/dist/scan.js +15 -1
  28. package/dist/scan.js.map +1 -1
  29. package/dist/scanners/api-security/index.d.ts +7 -0
  30. package/dist/scanners/api-security/index.d.ts.map +1 -0
  31. package/dist/scanners/api-security/index.js +139 -0
  32. package/dist/scanners/api-security/index.js.map +1 -0
  33. package/dist/scanners/api-security/index.test.d.ts +5 -0
  34. package/dist/scanners/api-security/index.test.d.ts.map +1 -0
  35. package/dist/scanners/api-security/index.test.js +360 -0
  36. package/dist/scanners/api-security/index.test.js.map +1 -0
  37. package/dist/scanners/api-security/patterns.d.ts +32 -0
  38. package/dist/scanners/api-security/patterns.d.ts.map +1 -0
  39. package/dist/scanners/api-security/patterns.js +159 -0
  40. package/dist/scanners/api-security/patterns.js.map +1 -0
  41. package/dist/scanners/authentication/index.d.ts +7 -0
  42. package/dist/scanners/authentication/index.d.ts.map +1 -0
  43. package/dist/scanners/authentication/index.js +107 -0
  44. package/dist/scanners/authentication/index.js.map +1 -0
  45. package/dist/scanners/authentication/index.test.d.ts +5 -0
  46. package/dist/scanners/authentication/index.test.d.ts.map +1 -0
  47. package/dist/scanners/authentication/index.test.js +379 -0
  48. package/dist/scanners/authentication/index.test.js.map +1 -0
  49. package/dist/scanners/authentication/patterns.d.ts +32 -0
  50. package/dist/scanners/authentication/patterns.d.ts.map +1 -0
  51. package/dist/scanners/authentication/patterns.js +133 -0
  52. package/dist/scanners/authentication/patterns.js.map +1 -0
  53. package/dist/scanners/configuration/index.d.ts +8 -0
  54. package/dist/scanners/configuration/index.d.ts.map +1 -0
  55. package/dist/scanners/configuration/index.js +87 -0
  56. package/dist/scanners/configuration/index.js.map +1 -0
  57. package/dist/scanners/configuration/index.test.d.ts +5 -0
  58. package/dist/scanners/configuration/index.test.d.ts.map +1 -0
  59. package/dist/scanners/configuration/index.test.js +344 -0
  60. package/dist/scanners/configuration/index.test.js.map +1 -0
  61. package/dist/scanners/configuration/patterns.d.ts +32 -0
  62. package/dist/scanners/configuration/patterns.d.ts.map +1 -0
  63. package/dist/scanners/configuration/patterns.js +146 -0
  64. package/dist/scanners/configuration/patterns.js.map +1 -0
  65. package/dist/scanners/credentials/index.d.ts +7 -0
  66. package/dist/scanners/credentials/index.d.ts.map +1 -0
  67. package/dist/scanners/credentials/index.js +129 -0
  68. package/dist/scanners/credentials/index.js.map +1 -0
  69. package/dist/scanners/credentials/index.test.d.ts +5 -0
  70. package/dist/scanners/credentials/index.test.d.ts.map +1 -0
  71. package/dist/scanners/credentials/index.test.js +395 -0
  72. package/dist/scanners/credentials/index.test.js.map +1 -0
  73. package/dist/scanners/credentials/patterns.d.ts +32 -0
  74. package/dist/scanners/credentials/patterns.d.ts.map +1 -0
  75. package/dist/scanners/credentials/patterns.js +140 -0
  76. package/dist/scanners/credentials/patterns.js.map +1 -0
  77. package/dist/scanners/errors/index.d.ts +8 -0
  78. package/dist/scanners/errors/index.d.ts.map +1 -0
  79. package/dist/scanners/errors/index.js +78 -0
  80. package/dist/scanners/errors/index.js.map +1 -0
  81. package/dist/scanners/errors/index.test.d.ts +5 -0
  82. package/dist/scanners/errors/index.test.d.ts.map +1 -0
  83. package/dist/scanners/errors/index.test.js +330 -0
  84. package/dist/scanners/errors/index.test.js.map +1 -0
  85. package/dist/scanners/errors/patterns.d.ts +27 -0
  86. package/dist/scanners/errors/patterns.d.ts.map +1 -0
  87. package/dist/scanners/errors/patterns.js +97 -0
  88. package/dist/scanners/errors/patterns.js.map +1 -0
  89. package/dist/scanners/hipaa2026/index.d.ts +8 -0
  90. package/dist/scanners/hipaa2026/index.d.ts.map +1 -0
  91. package/dist/scanners/hipaa2026/index.js +345 -0
  92. package/dist/scanners/hipaa2026/index.js.map +1 -0
  93. package/dist/scanners/hipaa2026/index.test.d.ts +5 -0
  94. package/dist/scanners/hipaa2026/index.test.d.ts.map +1 -0
  95. package/dist/scanners/hipaa2026/index.test.js +332 -0
  96. package/dist/scanners/hipaa2026/index.test.js.map +1 -0
  97. package/dist/scanners/hipaa2026/patterns.d.ts +57 -0
  98. package/dist/scanners/hipaa2026/patterns.d.ts.map +1 -0
  99. package/dist/scanners/hipaa2026/patterns.js +268 -0
  100. package/dist/scanners/hipaa2026/patterns.js.map +1 -0
  101. package/dist/scanners/operational/index.d.ts +7 -0
  102. package/dist/scanners/operational/index.d.ts.map +1 -0
  103. package/dist/scanners/operational/index.js +171 -0
  104. package/dist/scanners/operational/index.js.map +1 -0
  105. package/dist/scanners/operational/index.test.d.ts +5 -0
  106. package/dist/scanners/operational/index.test.d.ts.map +1 -0
  107. package/dist/scanners/operational/index.test.js +406 -0
  108. package/dist/scanners/operational/index.test.js.map +1 -0
  109. package/dist/scanners/operational/patterns.d.ts +33 -0
  110. package/dist/scanners/operational/patterns.d.ts.map +1 -0
  111. package/dist/scanners/operational/patterns.js +151 -0
  112. package/dist/scanners/operational/patterns.js.map +1 -0
  113. package/dist/scanners/rbac/index.d.ts +7 -0
  114. package/dist/scanners/rbac/index.d.ts.map +1 -0
  115. package/dist/scanners/rbac/index.js +145 -0
  116. package/dist/scanners/rbac/index.js.map +1 -0
  117. package/dist/scanners/rbac/index.test.d.ts +5 -0
  118. package/dist/scanners/rbac/index.test.d.ts.map +1 -0
  119. package/dist/scanners/rbac/index.test.js +422 -0
  120. package/dist/scanners/rbac/index.test.js.map +1 -0
  121. package/dist/scanners/rbac/patterns.d.ts +32 -0
  122. package/dist/scanners/rbac/patterns.d.ts.map +1 -0
  123. package/dist/scanners/rbac/patterns.js +124 -0
  124. package/dist/scanners/rbac/patterns.js.map +1 -0
  125. package/dist/scanners/revocation/index.d.ts +8 -0
  126. package/dist/scanners/revocation/index.d.ts.map +1 -0
  127. package/dist/scanners/revocation/index.js +83 -0
  128. package/dist/scanners/revocation/index.js.map +1 -0
  129. package/dist/scanners/revocation/index.test.d.ts +5 -0
  130. package/dist/scanners/revocation/index.test.d.ts.map +1 -0
  131. package/dist/scanners/revocation/index.test.js +332 -0
  132. package/dist/scanners/revocation/index.test.js.map +1 -0
  133. package/dist/scanners/revocation/patterns.d.ts +27 -0
  134. package/dist/scanners/revocation/patterns.d.ts.map +1 -0
  135. package/dist/scanners/revocation/patterns.js +109 -0
  136. package/dist/scanners/revocation/patterns.js.map +1 -0
  137. package/dist/scanners/sanitization/index.d.ts +8 -0
  138. package/dist/scanners/sanitization/index.d.ts.map +1 -0
  139. package/dist/scanners/sanitization/index.js +98 -0
  140. package/dist/scanners/sanitization/index.js.map +1 -0
  141. package/dist/scanners/sanitization/index.test.d.ts +5 -0
  142. package/dist/scanners/sanitization/index.test.d.ts.map +1 -0
  143. package/dist/scanners/sanitization/index.test.js +370 -0
  144. package/dist/scanners/sanitization/index.test.js.map +1 -0
  145. package/dist/scanners/sanitization/patterns.d.ts +27 -0
  146. package/dist/scanners/sanitization/patterns.d.ts.map +1 -0
  147. package/dist/scanners/sanitization/patterns.js +117 -0
  148. package/dist/scanners/sanitization/patterns.js.map +1 -0
  149. package/dist/training/certificate.d.ts +26 -0
  150. package/dist/training/certificate.d.ts.map +1 -0
  151. package/dist/training/certificate.js +92 -0
  152. package/dist/training/certificate.js.map +1 -0
  153. package/dist/training/index.d.ts +3 -0
  154. package/dist/training/index.d.ts.map +1 -0
  155. package/dist/training/index.js +243 -0
  156. package/dist/training/index.js.map +1 -0
  157. package/dist/training/modules.d.ts +13 -0
  158. package/dist/training/modules.d.ts.map +1 -0
  159. package/dist/training/modules.js +608 -0
  160. package/dist/training/modules.js.map +1 -0
  161. package/dist/training/questions.d.ts +9 -0
  162. package/dist/training/questions.d.ts.map +1 -0
  163. package/dist/training/questions.js +505 -0
  164. package/dist/training/questions.js.map +1 -0
  165. package/dist/types.d.ts +45 -0
  166. package/dist/types.d.ts.map +1 -1
  167. package/dist/utils/npm-audit.d.ts +6 -0
  168. package/dist/utils/npm-audit.d.ts.map +1 -0
  169. package/dist/utils/npm-audit.js +95 -0
  170. package/dist/utils/npm-audit.js.map +1 -0
  171. package/dist/utils/scan-history.d.ts +59 -0
  172. package/dist/utils/scan-history.d.ts.map +1 -0
  173. package/dist/utils/scan-history.js +170 -0
  174. package/dist/utils/scan-history.js.map +1 -0
  175. package/package.json +4 -1
  176. package/templates/baa-verification-letter.md +105 -0
  177. package/templates/irp.md +545 -0
  178. package/templates/notice-of-privacy-practices.md +491 -0
  179. package/templates/physical-safeguards-checklist.md +247 -0
  180. package/templates/security-officer-designation.md +237 -0
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Input Sanitization Security Detection Patterns
3
+ * Detects unsafe user input handling and file upload configurations
4
+ */
5
+ export interface SanitizationPattern {
6
+ id: string;
7
+ name: string;
8
+ description: string;
9
+ severity: 'critical' | 'high' | 'medium';
10
+ hipaaReference: string;
11
+ patterns: RegExp[];
12
+ negativePatterns?: RegExp[];
13
+ recommendation: string;
14
+ category: string;
15
+ }
16
+ /**
17
+ * SANITIZE-001: Unsanitized User Input in Database Operations
18
+ * Detects req.body/req.params/req.query used directly in DB operations
19
+ */
20
+ export declare const UNSANITIZED_DB_INPUT: SanitizationPattern;
21
+ /**
22
+ * SANITIZE-002: Insecure File Upload Configuration
23
+ * Detects file upload configuration without proper validation
24
+ */
25
+ export declare const INSECURE_FILE_UPLOAD: SanitizationPattern;
26
+ export declare const ALL_SANITIZATION_PATTERNS: SanitizationPattern[];
27
+ //# sourceMappingURL=patterns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patterns.d.ts","sourceRoot":"","sources":["../../../src/scanners/sanitization/patterns.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,CAAC;IACzC,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,mBA0ElC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,mBAgDlC,CAAC;AAEF,eAAO,MAAM,yBAAyB,EAAE,mBAAmB,EAG1D,CAAC"}
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Input Sanitization Security Detection Patterns
3
+ * Detects unsafe user input handling and file upload configurations
4
+ */
5
+ /**
6
+ * SANITIZE-001: Unsanitized User Input in Database Operations
7
+ * Detects req.body/req.params/req.query used directly in DB operations
8
+ */
9
+ export const UNSANITIZED_DB_INPUT = {
10
+ id: 'SANITIZE-001',
11
+ name: 'Unsanitized User Input in Database Operations',
12
+ description: 'User input from req.body, req.params, or req.query used directly in database operations (insert, update, query, sql, where) without validation (zod, yup, joi, validate, sanitize, parse)',
13
+ severity: 'critical',
14
+ hipaaReference: 'NPRM Anti-malware',
15
+ patterns: [
16
+ // Database operations with req.body - matches both .insert() and method calls
17
+ /(?:insert|update|query|sql|where|execute)\s*\([^)]*req\.body/i,
18
+ /(?:insert|update|query|sql|where|execute)\s*\([^)]*req\['body'\]/i,
19
+ // Database operations with req.params
20
+ /(?:insert|update|query|sql|where|execute)\s*\([^)]*req\.params/i,
21
+ /(?:insert|update|query|sql|where|execute)\s*\([^)]*req\['params'\]/i,
22
+ // Database operations with req.query
23
+ /(?:insert|update|query|sql|where|execute)\s*\([^)]*req\.query/i,
24
+ /(?:insert|update|query|sql|where|execute)\s*\([^)]*req\['query'\]/i,
25
+ // SQL template literals with user input
26
+ /(?:sql|query|execute)\s*`[^`]*\$\{req\.(?:body|params|query)/i,
27
+ // Raw SQL queries with concatenation
28
+ /(?:SELECT|INSERT|UPDATE|DELETE).*?\+\s*req\.(?:body|params|query)/i,
29
+ // Prisma operations with unsanitized input
30
+ /prisma\.\w+\.(?:create|update|upsert|delete)\s*\([^)]*req\.(?:body|params|query)/i,
31
+ // Mongoose operations with unsanitized input
32
+ /(?:create|findOneAndUpdate|updateOne|updateMany)\s*\([^)]*req\.(?:body|params|query)/i,
33
+ // TypeORM operations
34
+ /(?:save|insert|update)\s*\([^)]*req\.(?:body|params|query)/i,
35
+ // Knex operations
36
+ /knex\s*\([^)]*\)\.(?:insert|update|where)\s*\([^)]*req\.(?:body|params|query)/i,
37
+ // Generic database method calls with chaining like .values(), .set(), .data
38
+ /\.(?:values|set|data)\s*\([^)]*req\.(?:body|params|query)/i,
39
+ // Direct method calls like User.create(req.body)
40
+ /\w+\.create\s*\(\s*req\.(?:body|params|query)/i,
41
+ ],
42
+ negativePatterns: [
43
+ // Validation libraries
44
+ /zod/i,
45
+ /yup/i,
46
+ /joi/i,
47
+ /validate/i,
48
+ /sanitize/i,
49
+ /parse(?:Int|Float|Body)?/i,
50
+ /safeParse/i,
51
+ // Schema validation
52
+ /schema\.validate/i,
53
+ /\.schema\(/i,
54
+ // Type guards and checks
55
+ /typeof\s+/i,
56
+ /instanceof\s+/i,
57
+ // Validation middleware
58
+ /validationResult/i,
59
+ /express-validator/i,
60
+ // Safe wrappers
61
+ /sanitized/i,
62
+ /validated/i,
63
+ /checked/i,
64
+ ],
65
+ recommendation: 'Always validate and sanitize user input before database operations. Use validation libraries like Zod, Yup, or Joi. Example: const validated = schema.parse(req.body); await db.insert(validated). Never use raw req.body/params/query directly in database operations.',
66
+ category: 'access-control',
67
+ };
68
+ /**
69
+ * SANITIZE-002: Insecure File Upload Configuration
70
+ * Detects file upload configuration without proper validation
71
+ */
72
+ export const INSECURE_FILE_UPLOAD = {
73
+ id: 'SANITIZE-002',
74
+ name: 'Insecure File Upload Configuration',
75
+ description: 'File upload configuration (multer, formidable, busboy) missing fileFilter, limits, or MIME type validation',
76
+ severity: 'high',
77
+ hipaaReference: 'NPRM Anti-malware',
78
+ patterns: [
79
+ // Multer configuration (will check context for validation)
80
+ /multer\s*\(\s*\{/i,
81
+ // Formidable without file validation
82
+ /(?:new\s+)?formidable\.IncomingForm\s*\(/i,
83
+ /formidable\(\s*\(/i,
84
+ // Busboy without limits
85
+ /(?:new\s+)?Busboy\s*\(\s*\{/i,
86
+ /busboy\s*\(\s*\{/i,
87
+ ],
88
+ negativePatterns: [
89
+ // Has fileFilter
90
+ /fileFilter/i,
91
+ // Has limits
92
+ /limits\s*:/i,
93
+ /fileSize/i,
94
+ /maxFileSize/i,
95
+ // Has MIME type validation
96
+ /mimetype/i,
97
+ /mimeType/i,
98
+ /contentType/i,
99
+ /allowedTypes/i,
100
+ /allowedMimeTypes/i,
101
+ // File type checking
102
+ /\.endsWith\s*\(/i,
103
+ /\.includes\s*\(/i,
104
+ /test\s*\(/i, // regex test for file extensions
105
+ // Validation functions
106
+ /validateFile/i,
107
+ /checkFileType/i,
108
+ /isValidFile/i,
109
+ ],
110
+ recommendation: 'Configure file upload middleware with proper validation. Example: multer({ fileFilter: (req, file, cb) => { if (allowedMimes.includes(file.mimetype)) cb(null, true); else cb(new Error("Invalid file type")); }, limits: { fileSize: 5 * 1024 * 1024 } }). Always validate file type, size, and extension.',
111
+ category: 'access-control',
112
+ };
113
+ export const ALL_SANITIZATION_PATTERNS = [
114
+ UNSANITIZED_DB_INPUT,
115
+ INSECURE_FILE_UPLOAD,
116
+ ];
117
+ //# sourceMappingURL=patterns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patterns.js","sourceRoot":"","sources":["../../../src/scanners/sanitization/patterns.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAcH;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAwB;IACvD,EAAE,EAAE,cAAc;IAClB,IAAI,EAAE,+CAA+C;IACrD,WAAW,EACT,2LAA2L;IAC7L,QAAQ,EAAE,UAAU;IACpB,cAAc,EAAE,mBAAmB;IACnC,QAAQ,EAAE;QACR,8EAA8E;QAC9E,+DAA+D;QAC/D,mEAAmE;QAEnE,sCAAsC;QACtC,iEAAiE;QACjE,qEAAqE;QAErE,qCAAqC;QACrC,gEAAgE;QAChE,oEAAoE;QAEpE,wCAAwC;QACxC,+DAA+D;QAE/D,qCAAqC;QACrC,oEAAoE;QAEpE,2CAA2C;QAC3C,mFAAmF;QAEnF,6CAA6C;QAC7C,uFAAuF;QAEvF,qBAAqB;QACrB,6DAA6D;QAE7D,kBAAkB;QAClB,gFAAgF;QAEhF,4EAA4E;QAC5E,4DAA4D;QAE5D,iDAAiD;QACjD,gDAAgD;KACjD;IACD,gBAAgB,EAAE;QAChB,uBAAuB;QACvB,MAAM;QACN,MAAM;QACN,MAAM;QACN,WAAW;QACX,WAAW;QACX,2BAA2B;QAC3B,YAAY;QAEZ,oBAAoB;QACpB,mBAAmB;QACnB,aAAa;QAEb,yBAAyB;QACzB,YAAY;QACZ,gBAAgB;QAEhB,wBAAwB;QACxB,mBAAmB;QACnB,oBAAoB;QAEpB,gBAAgB;QAChB,YAAY;QACZ,YAAY;QACZ,UAAU;KACX;IACD,cAAc,EACZ,yQAAyQ;IAC3Q,QAAQ,EAAE,gBAAgB;CAC3B,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAwB;IACvD,EAAE,EAAE,cAAc;IAClB,IAAI,EAAE,oCAAoC;IAC1C,WAAW,EACT,4GAA4G;IAC9G,QAAQ,EAAE,MAAM;IAChB,cAAc,EAAE,mBAAmB;IACnC,QAAQ,EAAE;QACR,2DAA2D;QAC3D,mBAAmB;QAEnB,qCAAqC;QACrC,2CAA2C;QAC3C,oBAAoB;QAEpB,wBAAwB;QACxB,8BAA8B;QAC9B,mBAAmB;KACpB;IACD,gBAAgB,EAAE;QAChB,iBAAiB;QACjB,aAAa;QAEb,aAAa;QACb,aAAa;QACb,WAAW;QACX,cAAc;QAEd,2BAA2B;QAC3B,WAAW;QACX,WAAW;QACX,cAAc;QACd,eAAe;QACf,mBAAmB;QAEnB,qBAAqB;QACrB,kBAAkB;QAClB,kBAAkB;QAClB,YAAY,EAAE,iCAAiC;QAE/C,uBAAuB;QACvB,eAAe;QACf,gBAAgB;QAChB,cAAc;KACf;IACD,cAAc,EACZ,6SAA6S;IAC/S,QAAQ,EAAE,gBAAgB;CAC3B,CAAC;AAEF,MAAM,CAAC,MAAM,yBAAyB,GAA0B;IAC9D,oBAAoB;IACpB,oBAAoB;CACrB,CAAC"}
@@ -0,0 +1,26 @@
1
+ export interface Certificate {
2
+ name: string;
3
+ email?: string;
4
+ date: string;
5
+ score: number;
6
+ totalQuestions: number;
7
+ percentage: number;
8
+ moduleScores: Record<number, {
9
+ correct: number;
10
+ total: number;
11
+ percentage: number;
12
+ }>;
13
+ duration: number;
14
+ hash: string;
15
+ }
16
+ export declare function generateVerificationHash(certificate: Omit<Certificate, 'hash'>): string;
17
+ export declare function saveCertificate(name: string, email: string | undefined, score: number, totalQuestions: number, moduleScores: Record<number, {
18
+ correct: number;
19
+ total: number;
20
+ percentage: number;
21
+ }>, duration: number): Promise<{
22
+ certificate: Certificate;
23
+ path: string;
24
+ }>;
25
+ export declare function printCertificate(certificate: Certificate): string;
26
+ //# sourceMappingURL=certificate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"certificate.d.ts","sourceRoot":"","sources":["../../src/training/certificate.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAClB,MAAM,EACN;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CACvD,CAAC;IACF,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,GAAG,MAAM,CAUvF;AAED,wBAAsB,eAAe,CACnC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,KAAK,EAAE,MAAM,EACb,cAAc,EAAE,MAAM,EACtB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,EACpF,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,WAAW,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CA8BrD;AAED,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,CAoDjE"}
@@ -0,0 +1,92 @@
1
+ import { createHash } from 'crypto';
2
+ import { writeFile, mkdir } from 'fs/promises';
3
+ import { join } from 'path';
4
+ import { homedir } from 'os';
5
+ export function generateVerificationHash(certificate) {
6
+ const data = JSON.stringify({
7
+ name: certificate.name,
8
+ email: certificate.email,
9
+ date: certificate.date,
10
+ score: certificate.score,
11
+ totalQuestions: certificate.totalQuestions,
12
+ });
13
+ return createHash('sha256').update(data + 'vlayer-hipaa-training').digest('hex');
14
+ }
15
+ export async function saveCertificate(name, email, score, totalQuestions, moduleScores, duration) {
16
+ const date = new Date().toISOString();
17
+ const percentage = Math.round((score / totalQuestions) * 100);
18
+ const certificateData = {
19
+ name,
20
+ email,
21
+ date,
22
+ score,
23
+ totalQuestions,
24
+ percentage,
25
+ moduleScores,
26
+ duration,
27
+ };
28
+ const hash = generateVerificationHash(certificateData);
29
+ const certificate = { ...certificateData, hash };
30
+ // Save to .vlayer/training/ in home directory
31
+ const trainingDir = join(homedir(), '.vlayer', 'training');
32
+ await mkdir(trainingDir, { recursive: true });
33
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
34
+ const safeName = name.replace(/[^a-zA-Z0-9]/g, '_');
35
+ const filename = `${safeName}-${timestamp}.json`;
36
+ const filepath = join(trainingDir, filename);
37
+ await writeFile(filepath, JSON.stringify(certificate, null, 2), 'utf-8');
38
+ return { certificate, path: filepath };
39
+ }
40
+ export function printCertificate(certificate) {
41
+ const border = '═'.repeat(70);
42
+ const passed = certificate.percentage >= 70;
43
+ return `
44
+ ╔${border}╗
45
+ ║${' '.repeat(70)}║
46
+ ║${'CERTIFICATE OF COMPLETION'.padStart(42).padEnd(70)}║
47
+ ║${' '.repeat(70)}║
48
+ ║${'HIPAA Security Training for Developers'.padStart(44).padEnd(70)}║
49
+ ║${' '.repeat(70)}║
50
+ ╠${border}╣
51
+ ║${' '.repeat(70)}║
52
+ ║${'This certifies that'.padStart(33).padEnd(70)}║
53
+ ║${' '.repeat(70)}║
54
+ ║${certificate.name.toUpperCase().padStart((70 + certificate.name.length) / 2).padEnd(70)}║
55
+ ║${' '.repeat(70)}║
56
+ ║${'has successfully completed the vlayer HIPAA Security Training'.padStart(51).padEnd(70)}║
57
+ ║${' '.repeat(70)}║
58
+ ╠${border}╣
59
+ ║${' '.repeat(70)}║
60
+ ║ Date: ${new Date(certificate.date).toLocaleDateString('en-US', {
61
+ year: 'numeric',
62
+ month: 'long',
63
+ day: 'numeric',
64
+ }).padEnd(61)}║
65
+ ║ Score: ${certificate.score}/${certificate.totalQuestions} (${certificate.percentage}%)${' '.repeat(70 - 15 - certificate.score.toString().length - certificate.totalQuestions.toString().length - certificate.percentage.toString().length)}║
66
+ ║ Status: ${passed ? 'PASSED ✓' : 'NEEDS IMPROVEMENT'}${' '.repeat(58 - (passed ? 9 : 17))}║
67
+ ║ Duration: ${certificate.duration} minutes${' '.repeat(52 - certificate.duration.toString().length)}║
68
+ ║${' '.repeat(70)}║
69
+ ╠${border}╣
70
+ ║${' '.repeat(70)}║
71
+ ║ Module Breakdown:${' '.repeat(52)}║
72
+ ║${' '.repeat(70)}║
73
+ ${Object.entries(certificate.moduleScores)
74
+ .map(([moduleId, scores]) => {
75
+ const moduleNum = `Module ${moduleId}`.padEnd(12);
76
+ const scoreStr = `${scores.correct}/${scores.total} (${scores.percentage}%)`;
77
+ return `║ ${moduleNum}${scoreStr.padEnd(56)}║`;
78
+ })
79
+ .join('\n')}
80
+ ║${' '.repeat(70)}║
81
+ ╠${border}╣
82
+ ║${' '.repeat(70)}║
83
+ ║ Verification Hash:${' '.repeat(51)}║
84
+ ║ ${certificate.hash.substring(0, 60)}${' '.repeat(8)}║
85
+ ║ ${certificate.hash.substring(60)}${' '.repeat(70 - certificate.hash.substring(60).length - 2)}║
86
+ ║${' '.repeat(70)}║
87
+ ║${'Verify at: https://github.com/Francosimon53/verification-layer'.padEnd(70)}║
88
+ ║${' '.repeat(70)}║
89
+ ╚${border}╝
90
+ `;
91
+ }
92
+ //# sourceMappingURL=certificate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"certificate.js","sourceRoot":"","sources":["../../src/training/certificate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare function runTraining(): Promise<void>;
2
+ export declare function showTrainingStatus(): Promise<void>;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/training/index.ts"],"names":[],"mappings":"AAYA,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAyHjD;AAuJD,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CA8CxD"}
@@ -0,0 +1,243 @@
1
+ import inquirer from 'inquirer';
2
+ import chalk from 'chalk';
3
+ import { trainingModules } from './modules.js';
4
+ import { questions } from './questions.js';
5
+ import { saveCertificate, printCertificate } from './certificate.js';
6
+ export async function runTraining() {
7
+ console.clear();
8
+ console.log(chalk.bold.cyan('\n╔═══════════════════════════════════════════════════════════════════════╗'));
9
+ console.log(chalk.bold.cyan('║ ║'));
10
+ console.log(chalk.bold.cyan('║ HIPAA SECURITY TRAINING FOR DEVELOPERS ║'));
11
+ console.log(chalk.bold.cyan('║ ║'));
12
+ console.log(chalk.bold.cyan('╚═══════════════════════════════════════════════════════════════════════╝\n'));
13
+ console.log(chalk.white('Welcome to the HIPAA Security Training for Developers!\n'));
14
+ console.log(chalk.gray('This interactive training covers 10 essential modules on HIPAA compliance,'));
15
+ console.log(chalk.gray('security best practices, and secure coding for healthcare applications.\n'));
16
+ console.log(chalk.yellow('📚 10 modules covering PHI, encryption, access control, APIs, and more'));
17
+ console.log(chalk.yellow('❓ 45+ multiple-choice questions with explanations'));
18
+ console.log(chalk.yellow('🏆 Certificate of completion with verification hash'));
19
+ console.log(chalk.yellow('⏱️ Estimated time: 30-45 minutes\n'));
20
+ const { ready } = await inquirer.prompt([
21
+ {
22
+ type: 'confirm',
23
+ name: 'ready',
24
+ message: 'Are you ready to begin?',
25
+ default: true,
26
+ },
27
+ ]);
28
+ if (!ready) {
29
+ console.log(chalk.gray('\nTraining cancelled. Run "vlayer training" when you\'re ready.\n'));
30
+ return;
31
+ }
32
+ const { name, email } = await inquirer.prompt([
33
+ {
34
+ type: 'input',
35
+ name: 'name',
36
+ message: 'Enter your full name (for the certificate):',
37
+ validate: (input) => input.trim().length > 0 || 'Name is required',
38
+ },
39
+ {
40
+ type: 'input',
41
+ name: 'email',
42
+ message: 'Enter your email (optional):',
43
+ },
44
+ ]);
45
+ const startTime = Date.now();
46
+ let totalScore = 0;
47
+ const moduleScores = {};
48
+ // Run through each module
49
+ for (const module of trainingModules) {
50
+ console.clear();
51
+ await runModule(module);
52
+ // Get questions for this module
53
+ const moduleQuestions = questions.filter((q) => q.moduleId === module.id);
54
+ let moduleCorrect = 0;
55
+ for (const question of moduleQuestions) {
56
+ const isCorrect = await askQuestion(question);
57
+ if (isCorrect) {
58
+ moduleCorrect++;
59
+ totalScore++;
60
+ }
61
+ }
62
+ moduleScores[module.id] = {
63
+ correct: moduleCorrect,
64
+ total: moduleQuestions.length,
65
+ percentage: Math.round((moduleCorrect / moduleQuestions.length) * 100),
66
+ };
67
+ // Show module summary
68
+ const percentage = Math.round((moduleCorrect / moduleQuestions.length) * 100);
69
+ console.log(chalk.bold(`\n📊 Module ${module.id} Score: ${moduleCorrect}/${moduleQuestions.length} (${percentage}%)`));
70
+ if (percentage >= 80) {
71
+ console.log(chalk.green(' Excellent work! 🌟\n'));
72
+ }
73
+ else if (percentage >= 60) {
74
+ console.log(chalk.yellow(' Good effort! 👍\n'));
75
+ }
76
+ else {
77
+ console.log(chalk.red(' Review this module. 📚\n'));
78
+ }
79
+ if (module.id < trainingModules.length) {
80
+ const { continueTraining } = await inquirer.prompt([
81
+ {
82
+ type: 'confirm',
83
+ name: 'continueTraining',
84
+ message: 'Continue to next module?',
85
+ default: true,
86
+ },
87
+ ]);
88
+ if (!continueTraining) {
89
+ console.log(chalk.gray('\nTraining paused. Your progress has not been saved. Run "vlayer training" to start over.\n'));
90
+ return;
91
+ }
92
+ }
93
+ }
94
+ const endTime = Date.now();
95
+ const duration = Math.round((endTime - startTime) / 60000); // minutes
96
+ // Show final results
97
+ console.clear();
98
+ await showFinalResults(name, email || undefined, totalScore, questions.length, moduleScores, duration);
99
+ }
100
+ async function runModule(module) {
101
+ console.log(chalk.bold.cyan(`\n╔═══ MODULE ${module.id}: ${module.title.toUpperCase()} ${'═'.repeat(Math.max(0, 60 - module.title.length))}╗\n`));
102
+ console.log(chalk.white.bold(module.description + '\n'));
103
+ // Display content
104
+ for (const line of module.content) {
105
+ if (line === '') {
106
+ console.log('');
107
+ }
108
+ else {
109
+ console.log(chalk.gray(line));
110
+ }
111
+ }
112
+ // Display code examples if available
113
+ if (module.codeExamples && module.codeExamples.length > 0) {
114
+ for (const example of module.codeExamples) {
115
+ console.log(chalk.bold.red('\n❌ WRONG:\n'));
116
+ console.log(chalk.red(example.wrong));
117
+ console.log(chalk.bold.green('\n✅ RIGHT:\n'));
118
+ console.log(chalk.green(example.right));
119
+ console.log(chalk.bold('\n💡 Explanation:\n'));
120
+ console.log(chalk.gray(example.explanation));
121
+ }
122
+ }
123
+ console.log(chalk.bold.cyan(`\n╚${'═'.repeat(Math.max(0, 69))}╝\n`));
124
+ const { readyForQuestions } = await inquirer.prompt([
125
+ {
126
+ type: 'confirm',
127
+ name: 'readyForQuestions',
128
+ message: 'Ready for the questions?',
129
+ default: true,
130
+ },
131
+ ]);
132
+ if (!readyForQuestions) {
133
+ console.log(chalk.gray('Take your time. Press any key when ready...\n'));
134
+ await inquirer.prompt([
135
+ {
136
+ type: 'confirm',
137
+ name: 'continue',
138
+ message: 'Ready now?',
139
+ default: true,
140
+ },
141
+ ]);
142
+ }
143
+ console.log('');
144
+ }
145
+ async function askQuestion(question) {
146
+ const { answer } = await inquirer.prompt([
147
+ {
148
+ type: 'list',
149
+ name: 'answer',
150
+ message: question.question,
151
+ choices: question.options,
152
+ },
153
+ ]);
154
+ const selectedIndex = question.options.indexOf(answer);
155
+ const isCorrect = selectedIndex === question.correctAnswer;
156
+ if (isCorrect) {
157
+ console.log(chalk.green.bold(' ✓ Correct!\n'));
158
+ }
159
+ else {
160
+ console.log(chalk.red.bold(' ✗ Incorrect.\n'));
161
+ console.log(chalk.yellow(` The correct answer is: ${question.options[question.correctAnswer]}\n`));
162
+ }
163
+ console.log(chalk.gray(` 💡 ${question.explanation}\n`));
164
+ return isCorrect;
165
+ }
166
+ async function showFinalResults(name, email, score, total, moduleScores, duration) {
167
+ const percentage = Math.round((score / total) * 100);
168
+ const passed = percentage >= 70;
169
+ console.log(chalk.bold.cyan('\n╔═══════════════════════════════════════════════════════════════════════╗'));
170
+ console.log(chalk.bold.cyan('║ TRAINING COMPLETE! ║'));
171
+ console.log(chalk.bold.cyan('╚═══════════════════════════════════════════════════════════════════════╝\n'));
172
+ console.log(chalk.white(`Name: ${name}`));
173
+ if (email) {
174
+ console.log(chalk.white(`Email: ${email}`));
175
+ }
176
+ console.log(chalk.white(`Duration: ${duration} minutes\n`));
177
+ console.log(chalk.bold('📊 Final Score:\n'));
178
+ console.log(chalk.white(` ${score}/${total} questions correct (${percentage}%)\n`));
179
+ console.log(chalk.bold('📈 Module Breakdown:\n'));
180
+ for (const [moduleId, scores] of Object.entries(moduleScores)) {
181
+ const module = trainingModules.find((m) => m.id === parseInt(moduleId));
182
+ const bar = '█'.repeat(Math.round(scores.percentage / 5)) + '░'.repeat(20 - Math.round(scores.percentage / 5));
183
+ const color = scores.percentage >= 80 ? chalk.green : scores.percentage >= 60 ? chalk.yellow : chalk.red;
184
+ console.log(color(` Module ${moduleId}: ${module?.title.padEnd(45)} ${bar} ${scores.percentage}% (${scores.correct}/${scores.total})`));
185
+ }
186
+ console.log('');
187
+ if (passed) {
188
+ console.log(chalk.green.bold('🎉 CONGRATULATIONS! You passed the training!\n'));
189
+ console.log(chalk.green('You have successfully completed the HIPAA Security Training.'));
190
+ console.log(chalk.green('Your certificate has been generated below.\n'));
191
+ }
192
+ else {
193
+ console.log(chalk.yellow.bold('⚠️ You did not pass the training (70% required).\n'));
194
+ console.log(chalk.yellow('Review the modules and try again. Run "vlayer training" to restart.'));
195
+ console.log(chalk.yellow('Your score has been recorded but no certificate was generated.\n'));
196
+ return;
197
+ }
198
+ // Save certificate
199
+ const { certificate, path } = await saveCertificate(name, email, score, total, moduleScores, duration);
200
+ // Print certificate
201
+ console.log(chalk.cyan(printCertificate(certificate)));
202
+ console.log(chalk.gray(`\n📄 Certificate saved to: ${path}\n`));
203
+ console.log(chalk.gray('Share your verification hash to prove completion!\n'));
204
+ }
205
+ export async function showTrainingStatus() {
206
+ const { readdir } = await import('fs/promises');
207
+ const { join } = await import('path');
208
+ const { homedir } = await import('os');
209
+ const trainingDir = join(homedir(), '.vlayer', 'training');
210
+ try {
211
+ const files = await readdir(trainingDir);
212
+ const certificates = files.filter((f) => f.endsWith('.json'));
213
+ if (certificates.length === 0) {
214
+ console.log(chalk.yellow('\n⚠️ No training certificates found.\n'));
215
+ console.log(chalk.gray('Run "vlayer training" to complete the training and earn a certificate.\n'));
216
+ return;
217
+ }
218
+ console.log(chalk.bold.cyan('\n📚 Training Completion Status:\n'));
219
+ for (const certFile of certificates) {
220
+ const certPath = join(trainingDir, certFile);
221
+ const certContent = await import('fs/promises').then((fs) => fs.readFile(certPath, 'utf-8'));
222
+ const cert = JSON.parse(certContent);
223
+ const status = cert.percentage >= 70 ? chalk.green('✓ PASSED') : chalk.red('✗ FAILED');
224
+ const date = new Date(cert.date).toLocaleDateString('en-US', {
225
+ year: 'numeric',
226
+ month: 'short',
227
+ day: 'numeric',
228
+ });
229
+ console.log(chalk.white(`${status} ${cert.name.padEnd(30)} ${cert.percentage}% ${chalk.gray(`(${date})`)}`));
230
+ if (cert.email) {
231
+ console.log(chalk.gray(` ${cert.email}`));
232
+ }
233
+ console.log(chalk.gray(` Hash: ${cert.hash.substring(0, 40)}...`));
234
+ console.log('');
235
+ }
236
+ console.log(chalk.gray(`Total certificates: ${certificates.length}\n`));
237
+ }
238
+ catch (error) {
239
+ console.log(chalk.yellow('\n⚠️ No training records found.\n'));
240
+ console.log(chalk.gray('Run "vlayer training" to complete the training.\n'));
241
+ }
242
+ }
243
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/training/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export interface TrainingModule {
2
+ id: number;
3
+ title: string;
4
+ description: string;
5
+ content: string[];
6
+ codeExamples?: {
7
+ wrong: string;
8
+ right: string;
9
+ explanation: string;
10
+ }[];
11
+ }
12
+ export declare const trainingModules: TrainingModule[];
13
+ //# sourceMappingURL=modules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modules.d.ts","sourceRoot":"","sources":["../../src/training/modules.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,YAAY,CAAC,EAAE;QACb,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,EAAE,MAAM,CAAC;KACrB,EAAE,CAAC;CACL;AAED,eAAO,MAAM,eAAe,EAAE,cAAc,EAqmB3C,CAAC"}