orgnote-api 0.14.2 → 0.15.1

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.
@@ -4,7 +4,6 @@ exports[`Should decrypt note content via password 1`] = `
4
4
  [
5
5
  {
6
6
  "encrypted": false,
7
- "encryptionType": "gpgPassword",
8
7
  "id": "id",
9
8
  "meta": {
10
9
  "headings": [
@@ -28,7 +27,6 @@ exports[`Should decrypt note via provided keys 1`] = `
28
27
  [
29
28
  {
30
29
  "encrypted": false,
31
- "encryptionType": "gpgKeys",
32
30
  "id": "id",
33
31
  "meta": {
34
32
  "headings": [
@@ -48,6 +46,22 @@ exports[`Should decrypt note via provided keys 1`] = `
48
46
  ]
49
47
  `;
50
48
 
49
+ exports[`Should encrypt note and decrypt it into binary format 1`] = `
50
+ {
51
+ "author": {
52
+ "email": "test@mail.com",
53
+ "id": "1",
54
+ "name": "John Doe",
55
+ },
56
+ "encrypted": true,
57
+ "id": "id",
58
+ "meta": {
59
+ "id": undefined,
60
+ "published": false,
61
+ },
62
+ }
63
+ `;
64
+
51
65
  exports[`Should encrypt note content via password 1`] = `
52
66
  {
53
67
  "author": {
@@ -56,7 +70,38 @@ exports[`Should encrypt note content via password 1`] = `
56
70
  "name": "John Doe",
57
71
  },
58
72
  "encrypted": true,
59
- "encryptionType": "gpgPassword",
73
+ "id": "id",
74
+ "meta": {
75
+ "id": undefined,
76
+ "published": false,
77
+ },
78
+ }
79
+ `;
80
+
81
+ exports[`Should encrypt note content via password to binary format 1`] = `
82
+ {
83
+ "author": {
84
+ "email": "test@mail.com",
85
+ "id": "1",
86
+ "name": "John Doe",
87
+ },
88
+ "encrypted": true,
89
+ "id": "id",
90
+ "meta": {
91
+ "id": undefined,
92
+ "published": false,
93
+ },
94
+ }
95
+ `;
96
+
97
+ exports[`Should encrypt note to binary format 1`] = `
98
+ {
99
+ "author": {
100
+ "email": "test@mail.com",
101
+ "id": "1",
102
+ "name": "John Doe",
103
+ },
104
+ "encrypted": true,
60
105
  "id": "id",
61
106
  "meta": {
62
107
  "id": undefined,
@@ -73,7 +118,6 @@ exports[`Should encrypt note via keys 1`] = `
73
118
  "name": "John Doe",
74
119
  },
75
120
  "encrypted": true,
76
- "encryptionType": "gpgKeys",
77
121
  "id": "id",
78
122
  "meta": {
79
123
  "id": undefined,
@@ -130,7 +174,6 @@ exports[`Should not encrypt public note 1`] = `
130
174
  "name": "John Doe",
131
175
  },
132
176
  "encrypted": false,
133
- "encryptionType": "gpgPassword",
134
177
  "id": "id",
135
178
  "meta": {
136
179
  "description": "Awesome description",
@@ -145,7 +188,6 @@ exports[`Should set not encrypted status when params type does not provided 1`]
145
188
  [
146
189
  {
147
190
  "encrypted": true,
148
- "encryptionType": "gpgKeys",
149
191
  "id": "id",
150
192
  "meta": {
151
193
  "description": "Awesome description",
@@ -8,6 +8,9 @@ import {
8
8
  IncorrectOrMissingPrivateKeyPasswordError,
9
9
  encrypt,
10
10
  decrypt,
11
+ _encryptViaKeys,
12
+ armor,
13
+ unarmor,
11
14
  } from '../encryption';
12
15
  import { test, expect } from 'vitest';
13
16
 
@@ -16,21 +19,35 @@ import {
16
19
  armoredPrivateKey,
17
20
  privateKeyPassphrase,
18
21
  } from './encryption-keys';
22
+ // import { armor } from 'openpgp';
23
+
24
+ test('Should encrypt text as armored message via keys', async () => {
25
+ const res = await encryptViaKeys({
26
+ content: 'Hello world',
27
+ publicKey: armoredPublicKey,
28
+ privateKey: armoredPrivateKey,
29
+ privateKeyPassphrase: privateKeyPassphrase,
30
+ format: 'armored',
31
+ });
32
+
33
+ expect(res.startsWith('-----BEGIN PGP MESSAGE-----')).toBeTruthy();
34
+ });
19
35
 
20
36
  test('Should encrypt text via keys', async () => {
21
- const res = await encryptViaKeys(
22
- 'Hello world',
23
- armoredPublicKey,
24
- armoredPrivateKey,
25
- privateKeyPassphrase
26
- );
37
+ const res = await encryptViaKeys({
38
+ content: 'Hello world',
39
+ publicKey: armoredPublicKey,
40
+ privateKey: armoredPrivateKey,
41
+ privateKeyPassphrase,
42
+ format: 'armored',
43
+ });
27
44
 
28
45
  expect(res.startsWith('-----BEGIN PGP MESSAGE-----')).toBeTruthy();
29
46
  });
30
47
 
31
48
  test('Should decrypt via provided keys', async () => {
32
- const decryptedMessage = await decryptViaKeys(
33
- `-----BEGIN PGP MESSAGE-----
49
+ const decryptedMessage = await decryptViaKeys({
50
+ content: `-----BEGIN PGP MESSAGE-----
34
51
 
35
52
  wcFMA/vryg+TTn0rARAAhXuEjOHa856iCNVmdeIGHF+IEoeEwTc5tIcr6Lri
36
53
  V6xs//3WnwVwUlyxYrum3yCpx8t5gyWTXFfTNH08VoVqPVP45fkk1H7jdC6Q
@@ -62,15 +79,19 @@ YQ==
62
79
  =f4F1
63
80
  -----END PGP MESSAGE-----
64
81
  `,
65
- armoredPrivateKey,
66
- privateKeyPassphrase
67
- );
82
+ privateKey: armoredPrivateKey,
83
+ privateKeyPassphrase,
84
+ });
68
85
  expect(decryptedMessage).toEqual('Hello world');
69
86
  });
70
87
 
71
88
  test('Should encrypt via password', async () => {
72
89
  const password = 'test';
73
- const res = await encryptViaPassword('Hello world', password);
90
+ const res = await encryptViaPassword({
91
+ content: 'Hello world',
92
+ password,
93
+ format: 'armored',
94
+ });
74
95
 
75
96
  expect(res.startsWith('-----BEGIN PGP MESSAGE-----')).toBeTruthy();
76
97
  });
@@ -86,7 +107,7 @@ aGW80jwBXEQ7uTjT8akpOKiH7BIuhEUZIXh+vDveG0Uwf63s2dIklznAEo+E
86
107
  -----END PGP MESSAGE-----
87
108
  `;
88
109
 
89
- expect(await decryptViaPassword(encryptedMsg, password)).toEqual(
110
+ expect(await decryptViaPassword({ content: encryptedMsg, password })).toEqual(
90
111
  'Hello world'
91
112
  );
92
113
  });
@@ -125,14 +146,13 @@ YQ==
125
146
  -----END PGP MESSAGE-----`;
126
147
 
127
148
  try {
128
- await decryptViaPassword(encryptedMsg, 'password');
149
+ await decryptViaPassword({ content: encryptedMsg, password: 'password' });
129
150
  } catch (e) {
130
151
  expect(e).toBeInstanceOf(NoKeysProvidedError);
131
152
  }
132
153
  });
133
154
 
134
155
  test('Should raise IncorrectOrMissingPrivateKeyPasswordError error when incorrect armored key provided', async () => {
135
- const password = 'test';
136
156
  const encryptedMsg = `-----BEGIN PGP MESSAGE-----
137
157
 
138
158
  wy4ECQMI6KFWGqyVV+DgYl0qUEeTe1kAdjkoR4FxFJxx+6QiOP+sZ6h7bn//
@@ -143,7 +163,11 @@ aGW80jwBXEQ7uTjT8akpOKiH7BIuhEUZIXh+vDveG0Uwf63s2dIklznAEo+E
143
163
  `;
144
164
 
145
165
  try {
146
- await decryptViaKeys(encryptedMsg, armoredPublicKey, privateKeyPassphrase);
166
+ await decryptViaKeys({
167
+ content: encryptedMsg,
168
+ publicKey: armoredPublicKey,
169
+ privateKey: privateKeyPassphrase,
170
+ });
147
171
  } catch (e) {
148
172
  expect(e).toBeInstanceOf(IncorrectOrMissingPrivateKeyPasswordError);
149
173
  }
@@ -160,7 +184,11 @@ aGW80jwBXEQ7uTjT8akpOKiH7BIuhEUZIXh+vDveG0Uwf63s2dIklznAEo+E
160
184
  `;
161
185
 
162
186
  try {
163
- await decryptViaKeys(encryptedMsg, armoredPrivateKey, privateKeyPassphrase);
187
+ await decryptViaKeys({
188
+ content: encryptedMsg,
189
+ privateKey: armoredPrivateKey,
190
+ privateKeyPassphrase,
191
+ });
164
192
  } catch (e) {
165
193
  expect(e).toBeInstanceOf(NoPasswordProvidedError);
166
194
  }
@@ -170,14 +198,17 @@ test('Should encrypt and decrypt text by provided configs via password', async (
170
198
  const text = 'Hello world';
171
199
  const password = '123';
172
200
 
173
- const res = await encrypt(text, {
201
+ const res = await encrypt({
202
+ content: text,
174
203
  type: 'gpgPassword',
175
204
  password,
205
+ format: 'armored',
176
206
  });
177
207
 
178
208
  expect(res.startsWith('-----BEGIN PGP MESSAGE-----')).toBeTruthy();
179
209
 
180
- const decryptedMessage = await decrypt(res, {
210
+ const decryptedMessage = await decrypt({
211
+ content: res,
181
212
  type: 'gpgPassword',
182
213
  password,
183
214
  });
@@ -187,8 +218,10 @@ test('Should encrypt and decrypt text by provided configs via password', async (
187
218
 
188
219
  test('Should encrypt and decrypt text by provided configs via keys', async () => {
189
220
  const text = 'Hello world';
190
- const res = await encrypt(text, {
221
+ const res = await encrypt({
222
+ content: text,
191
223
  type: 'gpgKeys',
224
+ format: 'armored',
192
225
  publicKey: armoredPublicKey,
193
226
  privateKey: armoredPrivateKey,
194
227
  privateKeyPassphrase,
@@ -196,12 +229,103 @@ test('Should encrypt and decrypt text by provided configs via keys', async () =>
196
229
 
197
230
  expect(res.startsWith('-----BEGIN PGP MESSAGE-----')).toBeTruthy();
198
231
 
199
- const decryptedMessage = await decrypt(res, {
232
+ const decryptedMessage = await decrypt({
233
+ content: res,
200
234
  type: 'gpgKeys',
201
235
  publicKey: armoredPublicKey,
202
236
  privateKey: armoredPrivateKey,
203
237
  privateKeyPassphrase,
238
+ format: 'utf8',
239
+ });
240
+
241
+ expect(decryptedMessage).toEqual(text);
242
+ });
243
+
244
+ test('Should encrypt to binary and decrypt to format armored!', async () => {
245
+ const text = 'Hello world';
246
+
247
+ const res = await encrypt({
248
+ content: text,
249
+ type: 'gpgPassword',
250
+ password: '123',
251
+ format: 'binary',
252
+ });
253
+
254
+ expect(res).toBeInstanceOf(Uint8Array);
255
+
256
+ const decryptedMessage = await decrypt({
257
+ content: res,
258
+ type: 'gpgPassword',
259
+ format: 'utf8',
260
+ password: '123',
204
261
  });
205
262
 
206
263
  expect(decryptedMessage).toEqual(text);
207
264
  });
265
+
266
+ test('Should encrypt to binary and decrypt to binary format', async () => {
267
+ const text = 'Hello world';
268
+
269
+ const res = await encrypt({
270
+ content: text,
271
+ type: 'gpgPassword',
272
+ password: '123',
273
+ format: 'binary',
274
+ });
275
+
276
+ expect(res).toBeInstanceOf(Uint8Array);
277
+
278
+ const decryptedMessage = await decrypt({
279
+ content: res,
280
+ type: 'gpgPassword',
281
+ format: 'binary',
282
+ password: '123',
283
+ });
284
+
285
+ expect(decryptedMessage.toString()).toMatchInlineSnapshot(
286
+ `"72,101,108,108,111,32,119,111,114,108,100"`
287
+ );
288
+ });
289
+
290
+ test('Should encrypt to armored text and decrypt as binary format', async () => {
291
+ const text = 'Hello world';
292
+
293
+ const res = await encrypt({
294
+ content: text,
295
+ type: 'gpgPassword',
296
+ password: '123',
297
+ format: 'armored',
298
+ });
299
+
300
+ expect(res).toBeTypeOf('string');
301
+
302
+ const decryptedMessage = await decrypt({
303
+ content: res,
304
+ type: 'gpgPassword',
305
+ format: 'binary',
306
+ password: '123',
307
+ });
308
+
309
+ expect(decryptedMessage).toBeInstanceOf(Uint8Array);
310
+ });
311
+
312
+ test('Should armor and unarmor encrypted file', async () => {
313
+ const content: Uint8Array = new Uint8Array([
314
+ 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100,
315
+ ]);
316
+
317
+ const armored = armor(content);
318
+
319
+ expect(armored).toMatchInlineSnapshot(`
320
+ "-----BEGIN PGP MESSAGE-----
321
+
322
+ SGVsbG8gd29ybGQ=
323
+ =7asC
324
+ -----END PGP MESSAGE-----
325
+ "
326
+ `);
327
+
328
+ const { text, data } = await unarmor(armored);
329
+
330
+ expect(data).toEqual(content);
331
+ });
@@ -17,7 +17,6 @@ test('Should encrypt note content via password', async () => {
17
17
 
18
18
  const note: Note = {
19
19
  id: 'id',
20
- encryptionType: 'gpgPassword',
21
20
  meta: {
22
21
  title: 'My note title',
23
22
  images: [],
@@ -31,9 +30,11 @@ test('Should encrypt note content via password', async () => {
31
30
  },
32
31
  };
33
32
 
34
- const [encryptedNote, encryptedNoteText] = await encryptNote(note, noteText, {
33
+ const [encryptedNote, encryptedNoteText] = await encryptNote(note, {
34
+ content: noteText,
35
35
  type: 'gpgPassword',
36
36
  password: '123',
37
+ format: 'armored',
37
38
  });
38
39
 
39
40
  expect(encryptedNoteText.startsWith('-----BEGIN PGP MESSAGE-----')).toBe(
@@ -42,6 +43,39 @@ test('Should encrypt note content via password', async () => {
42
43
  expect(encryptedNote).toMatchSnapshot();
43
44
  });
44
45
 
46
+ test('Should encrypt note content via password to binary format', async () => {
47
+ const noteText = `#+ID: qweqwe
48
+
49
+ #+TITLE: Hello worlld
50
+
51
+ * Hello?`;
52
+
53
+ const note: Note = {
54
+ id: 'id',
55
+ meta: {
56
+ title: 'My note title',
57
+ images: [],
58
+ published: false,
59
+ description: 'Awesome description',
60
+ },
61
+ author: {
62
+ id: '1',
63
+ name: 'John Doe',
64
+ email: 'test@mail.com',
65
+ },
66
+ };
67
+
68
+ const [encryptedNote, encryptedNoteText] = await encryptNote(note, {
69
+ content: noteText,
70
+ type: 'gpgPassword',
71
+ password: '123',
72
+ format: 'binary',
73
+ });
74
+
75
+ expect(encryptedNote).toMatchSnapshot();
76
+ expect(encryptedNoteText).toBeInstanceOf(Uint8Array);
77
+ });
78
+
45
79
  test('Should decrypt note content via password', async () => {
46
80
  const noteText = `-----BEGIN PGP MESSAGE-----
47
81
 
@@ -51,9 +85,9 @@ zt3v0mABvaBJA7corlU8su21TpPApOs/+DMWpVlbI3Zer7QfQK1fSBoSTbCR
51
85
  5Bjlwt4ZhxFsh+c=
52
86
  =csID
53
87
  -----END PGP MESSAGE-----`;
88
+
54
89
  const note: Note = {
55
90
  id: 'id',
56
- encryptionType: 'gpgPassword',
57
91
  meta: {
58
92
  title: 'My note title',
59
93
  images: [],
@@ -62,7 +96,8 @@ zt3v0mABvaBJA7corlU8su21TpPApOs/+DMWpVlbI3Zer7QfQK1fSBoSTbCR
62
96
  },
63
97
  };
64
98
 
65
- const decryptedNote = await decryptNote(note, noteText, {
99
+ const decryptedNote = await decryptNote(note, {
100
+ content: noteText,
66
101
  type: 'gpgPassword',
67
102
  password: '123',
68
103
  });
@@ -70,7 +105,7 @@ zt3v0mABvaBJA7corlU8su21TpPApOs/+DMWpVlbI3Zer7QfQK1fSBoSTbCR
70
105
  expect(decryptedNote).toMatchSnapshot();
71
106
  });
72
107
 
73
- test.skip('Should encrypt note via keys', async () => {
108
+ test('Should encrypt note via keys', async () => {
74
109
  const noteText = `#+ID: qweqwe
75
110
  #+TITLE: Hello worlld
76
111
 
@@ -78,7 +113,6 @@ test.skip('Should encrypt note via keys', async () => {
78
113
 
79
114
  const note: Note = {
80
115
  id: 'id',
81
- encryptionType: 'gpgKeys',
82
116
  meta: {
83
117
  title: 'My note title for encryption via keys',
84
118
  images: [],
@@ -92,11 +126,13 @@ test.skip('Should encrypt note via keys', async () => {
92
126
  },
93
127
  };
94
128
 
95
- const [encryptedNote, encryptedNoteText] = await encryptNote(note, noteText, {
129
+ const [encryptedNote, encryptedNoteText] = await encryptNote(note, {
130
+ content: noteText,
96
131
  type: ModelsPublicNoteEncryptionTypeEnum.GpgKeys,
97
132
  publicKey: armoredPublicKey,
98
133
  privateKey: armoredPrivateKey,
99
134
  privateKeyPassphrase,
135
+ format: 'armored',
100
136
  });
101
137
 
102
138
  expect(encryptedNoteText.startsWith('-----BEGIN PGP MESSAGE-----')).toBe(
@@ -140,7 +176,6 @@ yEN8xpFUs7A9xryVZOosp9Sfe3IbBkO99sAQ7jV4EoMYk3/GKA==
140
176
 
141
177
  const note: Note = {
142
178
  id: 'id',
143
- encryptionType: 'gpgKeys',
144
179
  meta: {
145
180
  title: 'My note title for decryption via keys',
146
181
  images: [],
@@ -149,7 +184,8 @@ yEN8xpFUs7A9xryVZOosp9Sfe3IbBkO99sAQ7jV4EoMYk3/GKA==
149
184
  },
150
185
  };
151
186
 
152
- const decryptedNote = await decryptNote(note, encryptedNoteText, {
187
+ const decryptedNote = await decryptNote(note, {
188
+ content: encryptedNoteText,
153
189
  type: 'gpgKeys',
154
190
  publicKey: armoredPublicKey,
155
191
  privateKey: armoredPrivateKey,
@@ -167,7 +203,6 @@ test('Should not encrypt public note', async () => {
167
203
 
168
204
  const note: Note = {
169
205
  id: 'id',
170
- encryptionType: 'gpgPassword',
171
206
  meta: {
172
207
  title: 'My note title',
173
208
  images: [],
@@ -181,9 +216,11 @@ test('Should not encrypt public note', async () => {
181
216
  },
182
217
  };
183
218
 
184
- const [encryptedNote, encryptedNoteText] = await encryptNote(note, noteText, {
219
+ const [encryptedNote, encryptedNoteText] = await encryptNote(note, {
220
+ content: noteText,
185
221
  type: 'gpgPassword',
186
222
  password: '123',
223
+ format: 'armored',
187
224
  });
188
225
 
189
226
  expect(encryptedNoteText.startsWith('-----BEGIN PGP MESSAGE-----')).toBe(
@@ -213,9 +250,11 @@ test('Should encrypt note with empty encrypted property', async () => {
213
250
  },
214
251
  };
215
252
 
216
- const [encryptedNote, encryptedNoteText] = await encryptNote(note, noteText, {
253
+ const [encryptedNote, encryptedNoteText] = await encryptNote(note, {
254
+ content: noteText,
217
255
  type: 'gpgPassword',
218
256
  password: '123',
257
+ format: 'armored',
219
258
  });
220
259
 
221
260
  expect(encryptedNoteText.startsWith('-----BEGIN PGP MESSAGE-----')).toBe(
@@ -246,9 +285,11 @@ test('Should not decrypt note without provided encrypted type', async () => {
246
285
  },
247
286
  };
248
287
 
249
- const decryptedInfo = await decryptNote(note, noteText, {
288
+ const decryptedInfo = await decryptNote(note, {
289
+ content: noteText,
250
290
  type: 'gpgPassword',
251
291
  password: '123',
292
+ format: 'armored',
252
293
  });
253
294
 
254
295
  expect(decryptedInfo).toMatchSnapshot();
@@ -265,7 +306,6 @@ test('Should decrypt note and note meta', async () => {
265
306
  const note: Note = {
266
307
  id: 'id',
267
308
  meta: { ...meta },
268
- encryptionType: 'gpgPassword',
269
309
  };
270
310
 
271
311
  const noteText = `#+TITLE: My note title
@@ -277,19 +317,17 @@ test('Should decrypt note and note meta', async () => {
277
317
 
278
318
  Hello world`;
279
319
 
280
- const [encryptedNote, encryptedNoteText] = await encryptNote(note, noteText, {
320
+ const [encryptedNote, encryptedNoteText] = await encryptNote(note, {
321
+ content: noteText,
281
322
  type: 'gpgPassword',
282
323
  password: '123',
283
324
  });
284
325
 
285
- const [decryptedNote, decryptedNoteText] = await decryptNote(
286
- encryptedNote,
287
- encryptedNoteText,
288
- {
289
- type: 'gpgPassword',
290
- password: '123',
291
- }
292
- );
326
+ const [decryptedNote, decryptedNoteText] = await decryptNote(encryptedNote, {
327
+ content: encryptedNoteText,
328
+ type: 'gpgPassword',
329
+ password: '123',
330
+ });
293
331
 
294
332
  expect(decryptedNote.meta).toEqual(meta);
295
333
  expect(decryptedNoteText).toEqual(noteText);
@@ -298,7 +336,6 @@ Hello world`;
298
336
  test('Should set not encrypted status when params type does not provided', async () => {
299
337
  const note: Note = {
300
338
  id: 'id',
301
- encryptionType: 'gpgKeys',
302
339
  meta: {
303
340
  title: 'My note title for decryption via keys',
304
341
  images: [],
@@ -339,9 +376,50 @@ yEN8xpFUs7A9xryVZOosp9Sfe3IbBkO99sAQ7jV4EoMYk3/GKA==
339
376
  =LjkG
340
377
  -----END PGP MESSAGE-----`;
341
378
 
342
- const decryptedNote = await decryptNote(note, noteText, {
379
+ const decryptedNote = await decryptNote(note, {
380
+ content: noteText,
343
381
  type: 'disabled',
344
382
  });
345
383
 
346
384
  expect(decryptedNote).toMatchSnapshot();
347
385
  });
386
+
387
+ test('Should encrypt note to binary format', async () => {
388
+ const noteText = `#+ID: qweqwe
389
+ #+TITLE: Hello worlld
390
+
391
+ * Hello?`;
392
+
393
+ const note: Note = {
394
+ id: 'id',
395
+ meta: {
396
+ title: 'My note title',
397
+ images: [],
398
+ published: false,
399
+ description: 'Awesome description',
400
+ },
401
+ author: {
402
+ id: '1',
403
+ name: 'John Doe',
404
+ email: 'test@mail.com',
405
+ },
406
+ };
407
+
408
+ const [encryptedNote, encryptedNoteText] = await encryptNote(note, {
409
+ content: noteText,
410
+ type: 'gpgPassword',
411
+ password: '123',
412
+ format: 'binary',
413
+ });
414
+
415
+ expect(encryptedNoteText).toBeInstanceOf(Uint8Array);
416
+ expect(encryptedNote).toMatchSnapshot();
417
+
418
+ const [_, decryptedNoteText] = await decryptNote(encryptedNote, {
419
+ content: encryptedNoteText,
420
+ type: 'gpgPassword',
421
+ password: '123',
422
+ });
423
+
424
+ expect(decryptedNoteText).toEqual(noteText);
425
+ });
@@ -6,9 +6,16 @@ import {
6
6
  readKey,
7
7
  readMessage,
8
8
  readPrivateKey,
9
+ Stream,
9
10
  } from 'openpgp';
10
11
  import { ModelsPublicNoteEncryptionTypeEnum } from '../remote-api';
11
- import { OrgNoteEncryption } from '../models/encryption';
12
+ import {
13
+ OrgNoteEncryption,
14
+ OrgNotePasswordEncryption,
15
+ WithDecryptionContent,
16
+ } from '../models/encryption';
17
+ import { OrgNoteGpgEncryption, WithEncryptionContent } from 'src/models';
18
+ import { armor as _armor, unarmor as _unarmor, enums } from 'openpgp';
12
19
 
13
20
  export class IncorrectOrMissingPrivateKeyPasswordError extends Error {}
14
21
  export class ImpossibleToDecryptWithProvidedKeysError extends Error {}
@@ -43,74 +50,84 @@ export const encryptViaPassword = withCustomErrors(_encryptViaPassword);
43
50
  export const decryptViaPassword = withCustomErrors(_decryptViaPassword);
44
51
  export const decryptViaKeys = withCustomErrors(_decryptViaKeys);
45
52
 
46
- export const encrypt = async (
47
- text: string,
48
- encryptionParams: OrgNoteEncryption
49
- ): Promise<string> => {
53
+ export const encrypt = async <
54
+ T extends WithEncryptionContent<OrgNoteEncryption>,
55
+ >(
56
+ encryptionParams: T
57
+ ): Promise<T['format'] extends 'binary' ? Uint8Array : string> => {
50
58
  if (
51
59
  !encryptionParams.type ||
52
60
  encryptionParams.type === ModelsPublicNoteEncryptionTypeEnum.Disabled
53
61
  ) {
54
- return text;
62
+ return encryptionParams.content as any;
55
63
  }
56
- return encryptionParams.type === ModelsPublicNoteEncryptionTypeEnum.GpgKeys
57
- ? await encryptViaKeys(
58
- text,
59
- encryptionParams.publicKey,
60
- encryptionParams.privateKey,
61
- encryptionParams.privateKeyPassphrase
62
- )
63
- : await encryptViaPassword(text, encryptionParams.password);
64
+
65
+ const res = (encryptionParams.type ===
66
+ ModelsPublicNoteEncryptionTypeEnum.GpgKeys
67
+ ? await encryptViaKeys(encryptionParams)
68
+ : await encryptViaPassword(encryptionParams)) as unknown as Promise<
69
+ T['format'] extends 'binary' ? Uint8Array : string
70
+ >;
71
+
72
+ return res;
64
73
  };
65
74
 
66
- export const decrypt = async (
67
- text: string,
68
- encryptionParams: OrgNoteEncryption
69
- ): Promise<string> => {
75
+ export const decrypt = async <
76
+ T extends WithDecryptionContent<OrgNoteEncryption>,
77
+ >(
78
+ decryptionParams: T
79
+ ): Promise<T['format'] extends 'binary' ? Uint8Array : string> => {
70
80
  if (
71
- !encryptionParams.type ||
72
- encryptionParams.type === ModelsPublicNoteEncryptionTypeEnum.Disabled
81
+ !decryptionParams.type ||
82
+ decryptionParams.type === ModelsPublicNoteEncryptionTypeEnum.Disabled
73
83
  ) {
74
- return text;
84
+ return decryptionParams.content as any;
75
85
  }
76
- const decryptedNote =
77
- encryptionParams.type === ModelsPublicNoteEncryptionTypeEnum.GpgKeys
78
- ? await decryptViaKeys(
79
- text,
80
- encryptionParams.privateKey,
81
- encryptionParams.privateKeyPassphrase
82
- )
83
- : await decryptViaPassword(text, encryptionParams.password);
86
+ const decryptedNote = (decryptionParams.type ===
87
+ ModelsPublicNoteEncryptionTypeEnum.GpgKeys
88
+ ? await decryptViaKeys(decryptionParams)
89
+ : await decryptViaPassword(decryptionParams)) as unknown as Promise<
90
+ T['format'] extends 'binary' ? Uint8Array : string
91
+ >;
92
+
84
93
  return decryptedNote;
85
94
  };
86
95
 
87
- async function _encryptViaPassword(
88
- text: string,
89
- password: string
90
- ): Promise<string> {
96
+ async function _encryptViaPassword<
97
+ T extends WithEncryptionContent<OrgNotePasswordEncryption>,
98
+ >({
99
+ content,
100
+ password,
101
+ format = 'binary',
102
+ }: T): Promise<T['format'] extends 'binary' ? Uint8Array : string> {
91
103
  const message = await createMessage({
92
- text,
104
+ text: content,
93
105
  });
94
106
 
95
107
  const encryptedMessage = await _encrypt({
96
108
  message,
97
- format: 'armored',
109
+ format: format as any,
98
110
  passwords: [password],
99
111
  });
100
112
 
101
- return encryptedMessage.toString();
113
+ return encryptedMessage as Promise<
114
+ T['format'] extends 'binary' ? Uint8Array : string
115
+ >;
102
116
  }
103
117
 
104
- async function _encryptViaKeys(
105
- text: string,
106
- armoredPublicKey: string,
107
- armoredPrivateKey: string,
108
- privateKeyPassphrase?: string
109
- ): Promise<string> {
118
+ export async function _encryptViaKeys<
119
+ T extends WithEncryptionContent<OrgNoteGpgEncryption>,
120
+ >({
121
+ content,
122
+ publicKey: armoredPublicKey,
123
+ privateKey: armoredPrivateKey,
124
+ privateKeyPassphrase,
125
+ format = 'binary',
126
+ }: T): Promise<T['format'] extends 'binary' ? Uint8Array : string> {
110
127
  const publicKey = await readKey({ armoredKey: armoredPublicKey });
111
128
 
112
129
  const message = await createMessage({
113
- text,
130
+ text: content,
114
131
  });
115
132
 
116
133
  const encryptedPrivateKey = await readPrivateKey({
@@ -126,52 +143,73 @@ async function _encryptViaKeys(
126
143
 
127
144
  const encryptedMessage = await _encrypt({
128
145
  message,
129
- format: 'armored',
146
+ format: format as any,
130
147
  encryptionKeys: publicKey,
131
148
  signingKeys: privateKey,
132
149
  });
133
150
 
134
- return encryptedMessage.toString();
151
+ return encryptedMessage as Promise<
152
+ T['format'] extends 'binary' ? Uint8Array : string
153
+ >;
135
154
  }
136
155
 
137
- async function _decryptViaPassword(
138
- data: string,
139
- password: string
140
- ): Promise<string> {
141
- const message = await readMessage({ armoredMessage: data });
156
+ async function _decryptViaPassword<
157
+ T extends Omit<WithDecryptionContent<OrgNotePasswordEncryption>, 'type'>,
158
+ >({
159
+ content,
160
+ password,
161
+ format = 'utf8',
162
+ }: T): Promise<T['format'] extends 'binary' ? Uint8Array : string> {
163
+ const isArmoredContent = typeof content === 'string';
164
+
165
+ const message = await (isArmoredContent
166
+ ? readMessage({ armoredMessage: content })
167
+ : readMessage({ binaryMessage: content }));
142
168
 
143
169
  const { data: decryptedText } = await _decrypt({
144
170
  message,
171
+ format,
145
172
  passwords: password,
146
173
  });
147
174
 
148
- return decryptedText.toString();
175
+ return decryptedText as Promise<
176
+ T['format'] extends 'binary' ? Uint8Array : string
177
+ >;
149
178
  }
150
179
 
151
- async function _decryptViaKeys(
152
- data: string,
153
- armoredPrivateKey: string,
154
- privateKeyPassword?: string
155
- ): Promise<string> {
180
+ async function _decryptViaKeys<
181
+ T extends Omit<WithDecryptionContent<OrgNoteGpgEncryption>, 'type'>,
182
+ >({
183
+ privateKey: armoredPrivateKey,
184
+ privateKeyPassphrase,
185
+ content,
186
+ format = 'utf8',
187
+ }: T): Promise<T['format'] extends 'binary' ? Uint8Array : string> {
156
188
  const encryptedPrivateKey = await readPrivateKey({
157
189
  armoredKey: armoredPrivateKey,
158
190
  });
159
191
 
160
- const privateKey = privateKeyPassword
192
+ const privateKey = privateKeyPassphrase
161
193
  ? await decryptKey({
162
194
  privateKey: encryptedPrivateKey,
163
- passphrase: privateKeyPassword,
195
+ passphrase: privateKeyPassphrase,
164
196
  })
165
197
  : encryptedPrivateKey;
166
198
 
167
- const message = await readMessage({ armoredMessage: data });
199
+ const isString = typeof content === 'string';
200
+ const message = await (isString
201
+ ? readMessage({ armoredMessage: content })
202
+ : readMessage({ binaryMessage: content }));
168
203
 
169
204
  const { data: decryptedText } = await _decrypt({
170
205
  message,
206
+ format,
171
207
  decryptionKeys: privateKey,
172
208
  });
173
209
 
174
- return decryptedText.toString();
210
+ return decryptedText as Promise<
211
+ T['format'] extends 'binary' ? Uint8Array : string
212
+ >;
175
213
  }
176
214
 
177
215
  function withCustomErrors<P extends unknown[], T>(
@@ -213,3 +251,14 @@ function withCustomErrors<P extends unknown[], T>(
213
251
  }
214
252
  };
215
253
  }
254
+
255
+ // TODO: feat/native-encryption-support add custom error handling
256
+ export function armor(data: Uint8Array): string {
257
+ return _armor(enums.armor.message, data);
258
+ }
259
+
260
+ export async function unarmor(
261
+ data: string
262
+ ): Promise<{ text: string; data: Stream<Uint8Array>; type: enums.armor }> {
263
+ return await _unarmor(data);
264
+ }
@@ -1,22 +1,16 @@
1
- import {
2
- ModelsPublicNote,
3
- ModelsPublicNoteEncryptionTypeEnum,
4
- } from '../remote-api';
1
+ import { ModelsPublicNoteEncryptionTypeEnum } from '../remote-api';
5
2
 
3
+ import { decrypt, encrypt } from './encryption';
6
4
  import {
7
- decryptViaKeys,
8
- decryptViaPassword,
9
- encryptViaKeys,
10
- encryptViaPassword,
11
- } from './encryption';
12
- import { OrgNoteEncryption } from '../models/encryption';
5
+ OrgNoteEncryption,
6
+ WithDecryptionContent,
7
+ WithEncryptionContent,
8
+ WithNoteDecryptionContent,
9
+ } from '../models/encryption';
13
10
  import { parse, withMetaInfo } from 'org-mode-ast';
14
11
  import { isGpgEncrypted } from '..';
15
12
 
16
- export type NoteEncryptionType = `${ModelsPublicNote['encryptionType']}`;
17
-
18
13
  export interface AbstractEncryptedNote {
19
- encryptionType?: NoteEncryptionType;
20
14
  encrypted?: boolean;
21
15
  meta: {
22
16
  [key: string]: any;
@@ -29,8 +23,7 @@ export type EncryptionResult<T> = Promise<[T, string]>;
29
23
  // TODO: master change signature for encrypt notes without content
30
24
  export async function encryptNote<T extends AbstractEncryptedNote>(
31
25
  note: T,
32
- noteText: string,
33
- encryptionParams: OrgNoteEncryption
26
+ encryptionParams: WithEncryptionContent<OrgNoteEncryption>
34
27
  ): EncryptionResult<T> {
35
28
  note.encrypted = false;
36
29
  if (
@@ -38,132 +31,47 @@ export async function encryptNote<T extends AbstractEncryptedNote>(
38
31
  encryptionParams.type === ModelsPublicNoteEncryptionTypeEnum.Disabled ||
39
32
  note.meta.published
40
33
  ) {
41
- return [note, noteText];
34
+ return [note, encryptionParams.content];
42
35
  }
43
36
 
44
37
  note.meta = { id: note.meta.id, published: note.meta.published };
45
38
 
46
- const [encryptedNote, encryptedNoteText] =
47
- encryptionParams.type === ModelsPublicNoteEncryptionTypeEnum.GpgKeys
48
- ? await encryptNoteViaKeys(
49
- note,
50
- encryptionParams.publicKey,
51
- encryptionParams.privateKey,
52
- encryptionParams.privateKeyPassphrase
53
- )
54
- : await encryptNoteViaPassword(note, noteText, encryptionParams.password);
39
+ const encryptedContent = await encrypt(encryptionParams);
55
40
 
56
- encryptedNote.encrypted = true;
57
- return [encryptedNote, encryptedNoteText];
58
- }
59
- export async function encryptNoteViaPassword<T extends AbstractEncryptedNote>(
60
- note: T,
61
- noteText: string,
62
- password: string
63
- ): Promise<[T, string]> {
64
- const encryptedNoteText = await encryptViaPassword(noteText, password);
65
- return [
66
- {
67
- ...note,
68
- encrypted: ModelsPublicNoteEncryptionTypeEnum.GpgPassword,
69
- },
70
- encryptedNoteText,
71
- ];
72
- }
41
+ const encryptedNote = { ...note, encrypted: true };
73
42
 
74
- export async function encryptNoteViaKeys<T extends AbstractEncryptedNote>(
75
- note: T,
76
- noteText: string,
77
- publicKey: string,
78
- privateKey: string,
79
- privateKeyPassphrase?: string
80
- ): Promise<[T, string]> {
81
- const encryptedNoteText = await encryptViaKeys(
82
- noteText,
83
- publicKey,
84
- privateKey,
85
- privateKeyPassphrase
86
- );
87
-
88
- return [
89
- {
90
- ...note,
91
- encrypted: ModelsPublicNoteEncryptionTypeEnum.GpgKeys,
92
- },
93
- encryptedNoteText,
94
- ];
43
+ return [encryptedNote, encryptedContent];
95
44
  }
96
45
 
97
46
  export async function decryptNote<T extends AbstractEncryptedNote>(
98
47
  note: T,
99
- noteText: string,
100
- encryptionParams: OrgNoteEncryption
48
+ encryptionParams: WithNoteDecryptionContent<OrgNoteEncryption>
101
49
  ): EncryptionResult<T> {
102
- const isContentEncrypted = isGpgEncrypted(noteText);
50
+ const isContentEncrypted = isGpgEncrypted(encryptionParams.content);
103
51
  if (
104
52
  note.meta.published ||
105
- !note.encryptionType ||
106
53
  !encryptionParams.type ||
107
54
  encryptionParams.type === ModelsPublicNoteEncryptionTypeEnum.Disabled ||
108
55
  !isContentEncrypted
109
56
  ) {
110
57
  note.encrypted = isContentEncrypted;
111
- return [note, noteText];
58
+ return [note, encryptionParams.content];
112
59
  }
113
60
  note.encrypted = true;
114
- const [decryptedNote, decryptedNoteText] =
115
- encryptionParams.type === ModelsPublicNoteEncryptionTypeEnum.GpgKeys
116
- ? await decryptNoteViaKeys(
117
- note,
118
- noteText,
119
- encryptionParams.privateKey,
120
- encryptionParams.privateKeyPassphrase
121
- )
122
- : await decryptNoteViaPassword(note, noteText, encryptionParams.password);
61
+ const decryptionParams = {
62
+ ...encryptionParams,
63
+ format: 'utf8',
64
+ } as WithDecryptionContent<OrgNoteEncryption>;
123
65
 
66
+ const decryptedNoteText = await decrypt(decryptionParams);
124
67
  const parsed = withMetaInfo(parse(decryptedNoteText));
125
68
 
126
69
  return [
127
70
  {
128
- ...decryptedNote,
71
+ ...note,
129
72
  encrypted: false,
130
73
  meta: parsed.meta,
131
74
  },
132
75
  decryptedNoteText,
133
76
  ];
134
77
  }
135
-
136
- export async function decryptNoteViaPassword<T extends AbstractEncryptedNote>(
137
- note: T,
138
- noteText: string,
139
- password: string
140
- ): EncryptionResult<T> {
141
- const decryptedNoteText = await decryptViaPassword(noteText, password);
142
- return [
143
- {
144
- ...note,
145
- encrypted: ModelsPublicNoteEncryptionTypeEnum.GpgPassword,
146
- },
147
- decryptedNoteText,
148
- ];
149
- }
150
-
151
- export async function decryptNoteViaKeys<T extends AbstractEncryptedNote>(
152
- note: T,
153
- noteText: string,
154
- privateKey: string,
155
- privateKeyPassphrase?: string
156
- ): EncryptionResult<T> {
157
- const decryptedNoteText = await decryptViaKeys(
158
- noteText,
159
- privateKey,
160
- privateKeyPassphrase
161
- );
162
- return [
163
- {
164
- ...note,
165
- encrypted: ModelsPublicNoteEncryptionTypeEnum.GpgKeys,
166
- },
167
- decryptedNoteText,
168
- ];
169
- }
@@ -1,8 +1,20 @@
1
1
  import type { ModelsPublicNoteEncryptionTypeEnum } from '../remote-api';
2
2
 
3
+ export type EcnryptionFormat = 'binary' | 'armored';
4
+
5
+ export interface BaseOrgNoteEncryption {
6
+ format?: 'binary' | 'armored';
7
+ }
8
+
9
+ export interface BaseOrgNoteDecryption {
10
+ format?: 'utf8' | 'binary';
11
+ }
12
+
3
13
  export interface OrgNoteGpgEncryption {
4
14
  type: typeof ModelsPublicNoteEncryptionTypeEnum.GpgKeys;
15
+ /* Armored private key */
5
16
  privateKey: string;
17
+ /* Armored public key */
6
18
  publicKey: string;
7
19
  privateKeyPassphrase?: string;
8
20
  }
@@ -20,3 +32,19 @@ export type OrgNoteEncryption =
20
32
  | OrgNoteGpgEncryption
21
33
  | OrgNotePasswordEncryption
22
34
  | OrgNoteDisabledEncryption;
35
+
36
+ export type EncryptionData = {
37
+ content: string;
38
+ };
39
+
40
+ export type WithEncryptionContent<
41
+ T extends OrgNoteEncryption = OrgNoteEncryption,
42
+ > = T & EncryptionData & BaseOrgNoteEncryption;
43
+
44
+ export type WithDecryptionContent<
45
+ T extends OrgNoteEncryption = OrgNoteEncryption,
46
+ > = T & EncryptionData & BaseOrgNoteDecryption;
47
+
48
+ export type WithNoteDecryptionContent<
49
+ T extends OrgNoteEncryption = OrgNoteEncryption,
50
+ > = T & EncryptionData;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orgnote-api",
3
- "version": "0.14.2",
3
+ "version": "0.15.1",
4
4
  "description": "Official API for creating extensions for OrgNote app",
5
5
  "type": "module",
6
6
  "main": "./index.ts",
@@ -1,3 +1,6 @@
1
- export function isGpgEncrypted(text: string): boolean {
1
+ export function isGpgEncrypted(text: string | Uint8Array): boolean {
2
+ if (text instanceof Uint8Array) {
3
+ return true;
4
+ }
2
5
  return text.startsWith('-----BEGIN PGP MESSAGE-----');
3
6
  }