@hackthedev/dsync-sign 1.0.3 → 1.0.5

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 (2) hide show
  1. package/index.mjs +53 -17
  2. package/package.json +1 -1
package/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { promises as fs } from "fs";
1
+ import {promises as fs} from "fs";
2
2
  import crypto from "crypto";
3
3
 
4
4
  export class dSyncSign {
@@ -11,6 +11,7 @@ export class dSyncSign {
11
11
  if (x === null || typeof x !== "object") return x;
12
12
  if (Array.isArray(x)) return x.map(v => this.canonicalize(v));
13
13
  const out = {};
14
+
14
15
  for (const k of Object.keys(x).sort()) out[k] = this.canonicalize(x[k]);
15
16
  return out;
16
17
  }
@@ -19,48 +20,58 @@ export class dSyncSign {
19
20
  return JSON.stringify(this.canonicalize(obj));
20
21
  }
21
22
 
22
- clearWhiteSpaces(string) {
23
- return string.replace(/\s/g,'')
23
+ normalizePublicKey(key) {
24
+ return key
25
+ .replace(/\r|\n|\s+/g, '')
26
+ .replace('-----BEGINPUBLICKEY-----', '-----BEGIN PUBLIC KEY-----')
27
+ .replace('-----ENDPUBLICKEY-----', '-----END PUBLIC KEY-----')
28
+ .replace(/-----BEGIN PUBLIC KEY-----/, '-----BEGIN PUBLIC KEY-----\n')
29
+ .replace(/-----END PUBLIC KEY-----/, '\n-----END PUBLIC KEY-----')
30
+ .replace(/(.{64})/g, '$1\n')
31
+ .trim();
24
32
  }
25
33
 
26
34
  async ensureKeyPair() {
27
35
  try {
28
36
  const raw = await fs.readFile(this.KEY_FILE, "utf8");
29
- const { privateKey } = JSON.parse(raw);
37
+ const {privateKey} = JSON.parse(raw);
38
+
30
39
  crypto.createPrivateKey(privateKey);
31
- const pubKey = crypto.createPublicKey(privateKey).export({ type: "spki", format: "pem" });
32
- return { privateKey, publicKey: pubKey.toString() };
40
+
41
+ const pubKey = crypto.createPublicKey(privateKey).export({type: "spki", format: "pem"});
42
+ return {privateKey, publicKey: pubKey.toString()};
33
43
  } catch {
34
- const { privateKey, publicKey } = crypto.generateKeyPairSync("rsa", {
44
+ const {privateKey, publicKey} = crypto.generateKeyPairSync("rsa", {
35
45
  modulusLength: 2048,
36
- publicKeyEncoding: { type: "spki", format: "pem" },
37
- privateKeyEncoding: { type: "pkcs8", format: "pem" }
46
+ publicKeyEncoding: {type: "spki", format: "pem"},
47
+ privateKeyEncoding: {type: "pkcs8", format: "pem"}
38
48
  });
39
- await fs.writeFile(this.KEY_FILE, JSON.stringify({ privateKey }, null, 2), { encoding: "utf8", mode: 0o600 });
40
- return { privateKey, publicKey };
49
+
50
+ await fs.writeFile(this.KEY_FILE, JSON.stringify({privateKey}, null, 2), {encoding: "utf8", mode: 0o600});
51
+ return {privateKey, publicKey};
41
52
  }
42
53
  }
43
54
 
44
55
  async getPrivateKey() {
45
- const { privateKey } = await this.ensureKeyPair();
56
+ const {privateKey} = await this.ensureKeyPair();
46
57
  return privateKey;
47
58
  }
48
59
 
49
60
  async getPublicKey() {
50
- const { publicKey } = await this.ensureKeyPair();
61
+ const {publicKey} = await this.ensureKeyPair();
51
62
  return publicKey;
52
63
  }
53
64
 
54
65
  async encrypt(data, recipient) {
55
66
  const plaintext = typeof data === "string" ? data : this.stableStringify(data);
56
67
  let aesKey;
57
- let envelope = { method: "" };
68
+ let envelope = {method: ""};
58
69
 
59
70
  if (recipient.includes("BEGIN PUBLIC KEY") || recipient.includes("BEGIN RSA PUBLIC KEY")) {
60
71
  aesKey = crypto.randomBytes(32);
61
72
  envelope.method = "rsa";
62
73
  envelope.encKey = crypto.publicEncrypt(
63
- { key: recipient, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING },
74
+ {key: recipient, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING},
64
75
  aesKey
65
76
  ).toString("base64");
66
77
  } else {
@@ -70,7 +81,9 @@ export class dSyncSign {
70
81
  envelope.salt = salt.toString("base64");
71
82
  }
72
83
 
73
- const iv = crypto.randomBytes(16);
84
+ // Standard-konformer 12-Byte-IV (statt 16)
85
+ const iv = crypto.randomBytes(12);
86
+
74
87
  const cipher = crypto.createCipheriv("aes-256-gcm", aesKey, iv);
75
88
  const ciphertext = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
76
89
  const tag = cipher.getAuthTag();
@@ -88,7 +101,7 @@ export class dSyncSign {
88
101
  if (envelope.method === "rsa") {
89
102
  const priv = await this.getPrivateKey();
90
103
  aesKey = crypto.privateDecrypt(
91
- { key: priv, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING },
104
+ {key: priv, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING},
92
105
  Buffer.from(envelope.encKey, "base64")
93
106
  );
94
107
  } else if (envelope.method === "password") {
@@ -124,16 +137,20 @@ export class dSyncSign {
124
137
  const priv = await this.getPrivateKey();
125
138
  const signer = crypto.createSign("SHA256");
126
139
  const payload = typeof data === "string" ? data : this.stableStringify(data);
140
+
127
141
  signer.update(payload, "utf8");
128
142
  signer.end();
143
+
129
144
  return signer.sign(priv, "base64");
130
145
  }
131
146
 
132
147
  verifyData(data, signature, publicKey) {
133
148
  const verifier = crypto.createVerify("SHA256");
134
149
  const payload = typeof data === "string" ? data : this.stableStringify(data);
150
+
135
151
  verifier.update(payload, "utf8");
136
152
  verifier.end();
153
+
137
154
  return verifier.verify(publicKey, signature, "base64");
138
155
  }
139
156
 
@@ -142,8 +159,10 @@ export class dSyncSign {
142
159
  const re = /([^.\[\]]+)|\[(\d+)\]/g;
143
160
  const parts = [];
144
161
  let m;
162
+
145
163
  while ((m = re.exec(path)) !== null) parts.push(m[1] !== undefined ? m[1] : Number(m[2]));
146
164
  let cur = root;
165
+
147
166
  for (const p of parts) {
148
167
  if (cur == null) return undefined;
149
168
  cur = cur[p];
@@ -154,6 +173,7 @@ export class dSyncSign {
154
173
  cloneWithoutSig(obj) {
155
174
  if (obj == null || typeof obj !== "object") return obj;
156
175
  let copy;
176
+
157
177
  if (typeof structuredClone === "function") {
158
178
  try {
159
179
  copy = structuredClone(obj);
@@ -163,16 +183,19 @@ export class dSyncSign {
163
183
  } else {
164
184
  copy = JSON.parse(JSON.stringify(obj));
165
185
  }
186
+
166
187
  if (copy && Object.prototype.hasOwnProperty.call(copy, this.sigField)) delete copy[this.sigField];
167
188
  return copy;
168
189
  }
169
190
 
170
191
  async signJson(targetOrRoot, path) {
171
192
  let target = path ? this.getByPath(targetOrRoot, path) : targetOrRoot;
193
+
172
194
  if (target == null) {
173
195
  if (path) return false;
174
196
  throw new TypeError("target required");
175
197
  }
198
+
176
199
  if (Array.isArray(target)) {
177
200
  const out = [];
178
201
  for (const item of target) {
@@ -186,15 +209,18 @@ export class dSyncSign {
186
209
  }
187
210
  const payload = this.cloneWithoutSig(item);
188
211
  const s = await this.signData(payload);
212
+
189
213
  item[this.sigField] = s;
190
214
  out.push(s);
191
215
  }
192
216
  return out;
193
217
  }
218
+
194
219
  if (typeof target === "object") {
195
220
  if (Object.prototype.hasOwnProperty.call(target, this.sigField)) return target[this.sigField];
196
221
  const payload = this.cloneWithoutSig(target);
197
222
  const s = await this.signData(payload);
223
+
198
224
  target[this.sigField] = s;
199
225
  return s;
200
226
  }
@@ -203,28 +229,35 @@ export class dSyncSign {
203
229
 
204
230
  async verifyJson(targetOrRoot, publicKeyOrGetter, path) {
205
231
  let target = path ? this.getByPath(targetOrRoot, path) : targetOrRoot;
232
+
206
233
  if (target == null) {
207
234
  if (path) return false;
208
235
  throw new TypeError("target required");
209
236
  }
237
+
210
238
  if (Array.isArray(target)) {
211
239
  const out = [];
240
+
212
241
  for (const item of target) {
213
242
  if (item == null || typeof item !== "object") {
214
243
  out.push(false);
215
244
  continue;
216
245
  }
246
+
217
247
  if (!Object.prototype.hasOwnProperty.call(item, this.sigField)) {
218
248
  out.push(false);
219
249
  continue;
220
250
  }
251
+
221
252
  const signature = item[this.sigField];
222
253
  let pub = publicKeyOrGetter;
254
+
223
255
  if (typeof publicKeyOrGetter === "function") pub = await publicKeyOrGetter(item, targetOrRoot);
224
256
  if (!pub) {
225
257
  out.push(false);
226
258
  continue;
227
259
  }
260
+
228
261
  const payload = this.cloneWithoutSig(item);
229
262
  out.push(Boolean(this.verifyData(payload, signature, pub)));
230
263
  }
@@ -232,10 +265,13 @@ export class dSyncSign {
232
265
  }
233
266
  if (typeof target === "object") {
234
267
  if (!Object.prototype.hasOwnProperty.call(target, this.sigField)) return false;
268
+
235
269
  const signature = target[this.sigField];
236
270
  let pub = publicKeyOrGetter;
271
+
237
272
  if (typeof publicKeyOrGetter === "function") pub = await publicKeyOrGetter(target, targetOrRoot);
238
273
  if (!pub) return false;
274
+
239
275
  const payload = this.cloneWithoutSig(target);
240
276
  return Boolean(this.verifyData(payload, signature, pub));
241
277
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hackthedev/dsync-sign",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "",
5
5
  "main": "index.mjs",
6
6
  "type": "module",