@bdking71/spsignature 1.3.0 → 1.3.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.
package/README.md CHANGED
@@ -6,6 +6,8 @@
6
6
 
7
7
  > ⚠️ **NOT READY FOR PRODUCTION USE!** This module is currently under active development. Please do not use it in production environments at this time.
8
8
 
9
+ ![Approve Purchase Requisition Screen](/img/SignatureScreen.png)
10
+
9
11
  `@bdking71/spsignature` provides a secure, lightweight, and framework-agnostic digital signature module engineered specifically for Microsoft 365 environments. Built to run inside custom SPFx Web Parts and Extension Application Customizers, it delivers tamper-evident signature collection, automated base64 image encoding, and structured payload generation directly integrated with SharePoint Online list infrastructure.
10
12
 
11
13
  ---
@@ -33,7 +35,7 @@
33
35
 
34
36
  To enforce non-repudiation and meet compliance standards, `@bdking71/spsignature` includes a flexible Two-Factor Authentication engine. Rather than relying on rigid third-party SMS gateways, it delegates code delivery to **Power Automate**, allowing organizations to route standard **5-digit** verification codes via Microsoft Teams, Outlook Email, or both.
35
37
 
36
- ![Diagram illustrating the 2FA workflow between SPFx, SharePoint, and Power Automate](./img/tfa.jpg)
38
+ ![Diagram illustrating the 2FA workflow between SPFx, SharePoint, and Power Automate](/img/TFA.jpg)
37
39
 
38
40
  ### How the 2FA Workflow Operates
39
41
 
@@ -109,23 +109,34 @@ export declare function promptAndGenerateSecureAudit(context: SignerContext, mod
109
109
  export declare function getReportableSignature(compressedSignatureData: string): string;
110
110
  /**
111
111
  * Re-computes the SHA-256 hash of the audit envelope constructed from
112
- * the supplied parameters and compares it to `storedHash`.
112
+ * the supplied parameters and compares it to the stored hash.
113
113
  *
114
114
  * This allows any consumer to independently verify that a signed
115
115
  * record has not been tampered with, without needing access to the
116
116
  * original signature image.
117
117
  *
118
- * **Note:** Only top-level payload keys are sorted. If your payload
118
+ * **Note:** Only top-level payload keys are sorted. If your payload
119
119
  * contains nested objects whose key order may vary, consider using a
120
120
  * deep-sort utility before calling this function.
121
121
  *
122
- * @param payloadToVerify - The payload that was originally signed.
123
- * @param signer - The signer identifier used at sign time.
124
- * @param timestamp - The ISO-8601 timestamp captured at sign
125
- * time.
126
- * @param _compressedSignatureData - The compressed signature (unused by the
127
- * hash, retained for API symmetry).
128
- * @param storedHash - The SHA-256 hex digest to compare against.
129
- * @returns `true` if the recomputed hash matches `storedHash`.
122
+ * @param auditRecord - The SharePointAuditRecord returned from `promptAndGenerateSecureAudit`.
123
+ * @param signer - The signer's email address or display name (must match original signer).
124
+ * @param payload - The original payload object that was signed.
125
+ * @returns `true` if the signature hash is valid and authentic.
126
+ *
127
+ * @example
128
+ * ```ts
129
+ * const isValid = await verifySecureAuditRecord(
130
+ * auditRecord,
131
+ * "user@example.com",
132
+ * { amount: 1500, vendor: "Contoso" }
133
+ * );
134
+ *
135
+ * if (isValid) {
136
+ * console.log("Signature is authentic!");
137
+ * } else {
138
+ * console.warn("Signature has been tampered with!");
139
+ * }
140
+ * ```
130
141
  */
131
- export declare function verifySecureAuditRecord(payloadToVerify: Record<string, unknown>, signer: string, timestamp: string, _compressedSignatureData: string, storedHash: string): Promise<boolean>;
142
+ export declare function verifySecureAuditRecord(auditRecord: SharePointAuditRecord, signer: string, payload: Record<string, unknown>): Promise<boolean>;
@@ -1166,47 +1166,70 @@ function isCanvasEmpty(ctx, width, height) {
1166
1166
  // ---------------------------------------------------------------------------
1167
1167
  /**
1168
1168
  * Re-computes the SHA-256 hash of the audit envelope constructed from
1169
- * the supplied parameters and compares it to `storedHash`.
1169
+ * the supplied parameters and compares it to the stored hash.
1170
1170
  *
1171
1171
  * This allows any consumer to independently verify that a signed
1172
1172
  * record has not been tampered with, without needing access to the
1173
1173
  * original signature image.
1174
1174
  *
1175
- * **Note:** Only top-level payload keys are sorted. If your payload
1175
+ * **Note:** Only top-level payload keys are sorted. If your payload
1176
1176
  * contains nested objects whose key order may vary, consider using a
1177
1177
  * deep-sort utility before calling this function.
1178
1178
  *
1179
- * @param payloadToVerify - The payload that was originally signed.
1180
- * @param signer - The signer identifier used at sign time.
1181
- * @param timestamp - The ISO-8601 timestamp captured at sign
1182
- * time.
1183
- * @param _compressedSignatureData - The compressed signature (unused by the
1184
- * hash, retained for API symmetry).
1185
- * @param storedHash - The SHA-256 hex digest to compare against.
1186
- * @returns `true` if the recomputed hash matches `storedHash`.
1179
+ * @param auditRecord - The SharePointAuditRecord returned from `promptAndGenerateSecureAudit`.
1180
+ * @param signer - The signer's email address or display name (must match original signer).
1181
+ * @param payload - The original payload object that was signed.
1182
+ * @returns `true` if the signature hash is valid and authentic.
1183
+ *
1184
+ * @example
1185
+ * ```ts
1186
+ * const isValid = await verifySecureAuditRecord(
1187
+ * auditRecord,
1188
+ * "user@example.com",
1189
+ * { amount: 1500, vendor: "Contoso" }
1190
+ * );
1191
+ *
1192
+ * if (isValid) {
1193
+ * console.log("Signature is authentic!");
1194
+ * } else {
1195
+ * console.warn("Signature has been tampered with!");
1196
+ * }
1197
+ * ```
1187
1198
  */
1188
- async function verifySecureAuditRecord(payloadToVerify, signer, timestamp, _compressedSignatureData, storedHash) {
1199
+ async function verifySecureAuditRecord(auditRecord, signer, payload) {
1189
1200
  try {
1190
- if (!payloadToVerify || !storedHash)
1201
+ if (!auditRecord || !signer || !payload) {
1202
+ console.warn("verifySecureAuditRecord: Missing required parameters", {
1203
+ auditRecord: !!auditRecord,
1204
+ signer: !!signer,
1205
+ payload: !!payload,
1206
+ });
1191
1207
  return false;
1192
- const sortedPayloadString = JSON.stringify(payloadToVerify, Object.keys(payloadToVerify).sort());
1208
+ }
1209
+ // Sort payload keys for consistent hashing
1210
+ const sortedPayloadString = JSON.stringify(payload, Object.keys(payload).sort());
1211
+ // Reconstruct the canonical audit envelope
1193
1212
  const auditEnvelope = {
1194
1213
  payload: JSON.parse(sortedPayloadString),
1195
1214
  signer: signer.toLowerCase().trim(),
1196
- timestamp: timestamp.trim(),
1215
+ timestamp: auditRecord.signatureTimestamp.trim(),
1197
1216
  };
1217
+ // Hash the audit envelope
1198
1218
  const auditEnvelopeJson = JSON.stringify(auditEnvelope);
1199
1219
  const encoder = new TextEncoder();
1200
1220
  const encodedBytes = encoder.encode(auditEnvelopeJson);
1201
- // Fixed BufferSource type incompatibility:
1202
1221
  const hashBuffer = await window.crypto.subtle.digest("SHA-256", encodedBytes.buffer);
1203
1222
  const hashArray = Array.from(new Uint8Array(hashBuffer));
1204
1223
  const recomputedHash = hashArray
1205
1224
  .map((b) => b.toString(16).padStart(2, "0"))
1206
1225
  .join("");
1207
- return recomputedHash === storedHash.trim();
1226
+ // Compare hashes
1227
+ const isValid = recomputedHash === auditRecord.signatureHash.trim();
1228
+ console.log("verifySecureAuditRecord: Verification result =", isValid, "Recomputed hash =", recomputedHash.substring(0, 16) + "...");
1229
+ return isValid;
1208
1230
  }
1209
- catch (_a) {
1231
+ catch (error) {
1232
+ console.error("verifySecureAuditRecord: Error during verification", error);
1210
1233
  return false;
1211
1234
  }
1212
1235
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bdking71/spsignature",
3
- "version": "1.3.0",
3
+ "version": "1.3.4",
4
4
  "description": "SharePoint Framework isolated digital signing, LZW compression, and OTP audit engine.",
5
5
  "main": "lib/index.js",
6
6
  "module": "lib/index.js",