orgnote-api 0.14.1 → 0.15.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.
- package/api.ts +5 -1
- package/encryption/__tests__/__snapshots__/note-encryption.spec.ts.snap +48 -6
- package/encryption/__tests__/encryption.spec.ts +122 -21
- package/encryption/__tests__/note-encryption.spec.ts +103 -25
- package/encryption/encryption.ts +96 -60
- package/encryption/note-encryption.ts +22 -104
- package/models/encryption.ts +28 -0
- package/package.json +1 -1
- package/tools/is-gpg-encrypted.ts +4 -1
package/api.ts
CHANGED
|
@@ -103,7 +103,11 @@ export interface OrgNoteConfig {
|
|
|
103
103
|
language: string;
|
|
104
104
|
};
|
|
105
105
|
synchronization: {
|
|
106
|
-
type: 'none' | 'api'
|
|
106
|
+
type: 'none' | 'api';
|
|
107
|
+
};
|
|
108
|
+
vault: {
|
|
109
|
+
/* File system available only for mobile devices */
|
|
110
|
+
type: 'inmemory' | 'filesystem';
|
|
107
111
|
path?: string;
|
|
108
112
|
};
|
|
109
113
|
ui: {
|
|
@@ -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
|
-
"
|
|
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,7 @@ import {
|
|
|
8
8
|
IncorrectOrMissingPrivateKeyPasswordError,
|
|
9
9
|
encrypt,
|
|
10
10
|
decrypt,
|
|
11
|
+
_encryptViaKeys,
|
|
11
12
|
} from '../encryption';
|
|
12
13
|
import { test, expect } from 'vitest';
|
|
13
14
|
|
|
@@ -16,21 +17,35 @@ import {
|
|
|
16
17
|
armoredPrivateKey,
|
|
17
18
|
privateKeyPassphrase,
|
|
18
19
|
} from './encryption-keys';
|
|
20
|
+
// import { armor } from 'openpgp';
|
|
21
|
+
|
|
22
|
+
test('Should encrypt text as armored message via keys', async () => {
|
|
23
|
+
const res = await encryptViaKeys({
|
|
24
|
+
content: 'Hello world',
|
|
25
|
+
publicKey: armoredPublicKey,
|
|
26
|
+
privateKey: armoredPrivateKey,
|
|
27
|
+
privateKeyPassphrase: privateKeyPassphrase,
|
|
28
|
+
format: 'armored',
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
expect(res.startsWith('-----BEGIN PGP MESSAGE-----')).toBeTruthy();
|
|
32
|
+
});
|
|
19
33
|
|
|
20
34
|
test('Should encrypt text via keys', async () => {
|
|
21
|
-
const res = await encryptViaKeys(
|
|
22
|
-
'Hello world',
|
|
23
|
-
armoredPublicKey,
|
|
24
|
-
armoredPrivateKey,
|
|
25
|
-
privateKeyPassphrase
|
|
26
|
-
|
|
35
|
+
const res = await encryptViaKeys({
|
|
36
|
+
content: 'Hello world',
|
|
37
|
+
publicKey: armoredPublicKey,
|
|
38
|
+
privateKey: armoredPrivateKey,
|
|
39
|
+
privateKeyPassphrase,
|
|
40
|
+
format: 'armored',
|
|
41
|
+
});
|
|
27
42
|
|
|
28
43
|
expect(res.startsWith('-----BEGIN PGP MESSAGE-----')).toBeTruthy();
|
|
29
44
|
});
|
|
30
45
|
|
|
31
46
|
test('Should decrypt via provided keys', async () => {
|
|
32
|
-
const decryptedMessage = await decryptViaKeys(
|
|
33
|
-
`-----BEGIN PGP MESSAGE-----
|
|
47
|
+
const decryptedMessage = await decryptViaKeys({
|
|
48
|
+
content: `-----BEGIN PGP MESSAGE-----
|
|
34
49
|
|
|
35
50
|
wcFMA/vryg+TTn0rARAAhXuEjOHa856iCNVmdeIGHF+IEoeEwTc5tIcr6Lri
|
|
36
51
|
V6xs//3WnwVwUlyxYrum3yCpx8t5gyWTXFfTNH08VoVqPVP45fkk1H7jdC6Q
|
|
@@ -62,15 +77,19 @@ YQ==
|
|
|
62
77
|
=f4F1
|
|
63
78
|
-----END PGP MESSAGE-----
|
|
64
79
|
`,
|
|
65
|
-
armoredPrivateKey,
|
|
66
|
-
privateKeyPassphrase
|
|
67
|
-
);
|
|
80
|
+
privateKey: armoredPrivateKey,
|
|
81
|
+
privateKeyPassphrase,
|
|
82
|
+
});
|
|
68
83
|
expect(decryptedMessage).toEqual('Hello world');
|
|
69
84
|
});
|
|
70
85
|
|
|
71
86
|
test('Should encrypt via password', async () => {
|
|
72
87
|
const password = 'test';
|
|
73
|
-
const res = await encryptViaPassword(
|
|
88
|
+
const res = await encryptViaPassword({
|
|
89
|
+
content: 'Hello world',
|
|
90
|
+
password,
|
|
91
|
+
format: 'armored',
|
|
92
|
+
});
|
|
74
93
|
|
|
75
94
|
expect(res.startsWith('-----BEGIN PGP MESSAGE-----')).toBeTruthy();
|
|
76
95
|
});
|
|
@@ -86,7 +105,7 @@ aGW80jwBXEQ7uTjT8akpOKiH7BIuhEUZIXh+vDveG0Uwf63s2dIklznAEo+E
|
|
|
86
105
|
-----END PGP MESSAGE-----
|
|
87
106
|
`;
|
|
88
107
|
|
|
89
|
-
expect(await decryptViaPassword(encryptedMsg, password)).toEqual(
|
|
108
|
+
expect(await decryptViaPassword({ content: encryptedMsg, password })).toEqual(
|
|
90
109
|
'Hello world'
|
|
91
110
|
);
|
|
92
111
|
});
|
|
@@ -125,14 +144,13 @@ YQ==
|
|
|
125
144
|
-----END PGP MESSAGE-----`;
|
|
126
145
|
|
|
127
146
|
try {
|
|
128
|
-
await decryptViaPassword(encryptedMsg, 'password');
|
|
147
|
+
await decryptViaPassword({ content: encryptedMsg, password: 'password' });
|
|
129
148
|
} catch (e) {
|
|
130
149
|
expect(e).toBeInstanceOf(NoKeysProvidedError);
|
|
131
150
|
}
|
|
132
151
|
});
|
|
133
152
|
|
|
134
153
|
test('Should raise IncorrectOrMissingPrivateKeyPasswordError error when incorrect armored key provided', async () => {
|
|
135
|
-
const password = 'test';
|
|
136
154
|
const encryptedMsg = `-----BEGIN PGP MESSAGE-----
|
|
137
155
|
|
|
138
156
|
wy4ECQMI6KFWGqyVV+DgYl0qUEeTe1kAdjkoR4FxFJxx+6QiOP+sZ6h7bn//
|
|
@@ -143,7 +161,11 @@ aGW80jwBXEQ7uTjT8akpOKiH7BIuhEUZIXh+vDveG0Uwf63s2dIklznAEo+E
|
|
|
143
161
|
`;
|
|
144
162
|
|
|
145
163
|
try {
|
|
146
|
-
await decryptViaKeys(
|
|
164
|
+
await decryptViaKeys({
|
|
165
|
+
content: encryptedMsg,
|
|
166
|
+
publicKey: armoredPublicKey,
|
|
167
|
+
privateKey: privateKeyPassphrase,
|
|
168
|
+
});
|
|
147
169
|
} catch (e) {
|
|
148
170
|
expect(e).toBeInstanceOf(IncorrectOrMissingPrivateKeyPasswordError);
|
|
149
171
|
}
|
|
@@ -160,7 +182,11 @@ aGW80jwBXEQ7uTjT8akpOKiH7BIuhEUZIXh+vDveG0Uwf63s2dIklznAEo+E
|
|
|
160
182
|
`;
|
|
161
183
|
|
|
162
184
|
try {
|
|
163
|
-
await decryptViaKeys(
|
|
185
|
+
await decryptViaKeys({
|
|
186
|
+
content: encryptedMsg,
|
|
187
|
+
privateKey: armoredPrivateKey,
|
|
188
|
+
privateKeyPassphrase,
|
|
189
|
+
});
|
|
164
190
|
} catch (e) {
|
|
165
191
|
expect(e).toBeInstanceOf(NoPasswordProvidedError);
|
|
166
192
|
}
|
|
@@ -170,14 +196,17 @@ test('Should encrypt and decrypt text by provided configs via password', async (
|
|
|
170
196
|
const text = 'Hello world';
|
|
171
197
|
const password = '123';
|
|
172
198
|
|
|
173
|
-
const res = await encrypt(
|
|
199
|
+
const res = await encrypt({
|
|
200
|
+
content: text,
|
|
174
201
|
type: 'gpgPassword',
|
|
175
202
|
password,
|
|
203
|
+
format: 'armored',
|
|
176
204
|
});
|
|
177
205
|
|
|
178
206
|
expect(res.startsWith('-----BEGIN PGP MESSAGE-----')).toBeTruthy();
|
|
179
207
|
|
|
180
|
-
const decryptedMessage = await decrypt(
|
|
208
|
+
const decryptedMessage = await decrypt({
|
|
209
|
+
content: res,
|
|
181
210
|
type: 'gpgPassword',
|
|
182
211
|
password,
|
|
183
212
|
});
|
|
@@ -187,8 +216,10 @@ test('Should encrypt and decrypt text by provided configs via password', async (
|
|
|
187
216
|
|
|
188
217
|
test('Should encrypt and decrypt text by provided configs via keys', async () => {
|
|
189
218
|
const text = 'Hello world';
|
|
190
|
-
const res = await encrypt(
|
|
219
|
+
const res = await encrypt({
|
|
220
|
+
content: text,
|
|
191
221
|
type: 'gpgKeys',
|
|
222
|
+
format: 'armored',
|
|
192
223
|
publicKey: armoredPublicKey,
|
|
193
224
|
privateKey: armoredPrivateKey,
|
|
194
225
|
privateKeyPassphrase,
|
|
@@ -196,12 +227,82 @@ test('Should encrypt and decrypt text by provided configs via keys', async () =>
|
|
|
196
227
|
|
|
197
228
|
expect(res.startsWith('-----BEGIN PGP MESSAGE-----')).toBeTruthy();
|
|
198
229
|
|
|
199
|
-
const decryptedMessage = await decrypt(
|
|
230
|
+
const decryptedMessage = await decrypt({
|
|
231
|
+
content: res,
|
|
200
232
|
type: 'gpgKeys',
|
|
201
233
|
publicKey: armoredPublicKey,
|
|
202
234
|
privateKey: armoredPrivateKey,
|
|
203
235
|
privateKeyPassphrase,
|
|
236
|
+
format: 'utf8',
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
expect(decryptedMessage).toEqual(text);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
test('Should encrypt to binary and decrypt to format armored!', async () => {
|
|
243
|
+
const text = 'Hello world';
|
|
244
|
+
|
|
245
|
+
const res = await encrypt({
|
|
246
|
+
content: text,
|
|
247
|
+
type: 'gpgPassword',
|
|
248
|
+
password: '123',
|
|
249
|
+
format: 'binary',
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
expect(res).toBeInstanceOf(Uint8Array);
|
|
253
|
+
|
|
254
|
+
const decryptedMessage = await decrypt({
|
|
255
|
+
content: res,
|
|
256
|
+
type: 'gpgPassword',
|
|
257
|
+
format: 'utf8',
|
|
258
|
+
password: '123',
|
|
204
259
|
});
|
|
205
260
|
|
|
206
261
|
expect(decryptedMessage).toEqual(text);
|
|
207
262
|
});
|
|
263
|
+
|
|
264
|
+
test('Should encrypt to binary and decrypt to binary format', async () => {
|
|
265
|
+
const text = 'Hello world';
|
|
266
|
+
|
|
267
|
+
const res = await encrypt({
|
|
268
|
+
content: text,
|
|
269
|
+
type: 'gpgPassword',
|
|
270
|
+
password: '123',
|
|
271
|
+
format: 'binary',
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
expect(res).toBeInstanceOf(Uint8Array);
|
|
275
|
+
|
|
276
|
+
const decryptedMessage = await decrypt({
|
|
277
|
+
content: res,
|
|
278
|
+
type: 'gpgPassword',
|
|
279
|
+
format: 'binary',
|
|
280
|
+
password: '123',
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
expect(decryptedMessage.toString()).toMatchInlineSnapshot(
|
|
284
|
+
`"72,101,108,108,111,32,119,111,114,108,100"`
|
|
285
|
+
);
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
test('Should encrypt to armored text and decrypt as binary format', async () => {
|
|
289
|
+
const text = 'Hello world';
|
|
290
|
+
|
|
291
|
+
const res = await encrypt({
|
|
292
|
+
content: text,
|
|
293
|
+
type: 'gpgPassword',
|
|
294
|
+
password: '123',
|
|
295
|
+
format: 'armored',
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
expect(res).toBeTypeOf('string');
|
|
299
|
+
|
|
300
|
+
const decryptedMessage = await decrypt({
|
|
301
|
+
content: res,
|
|
302
|
+
type: 'gpgPassword',
|
|
303
|
+
format: 'binary',
|
|
304
|
+
password: '123',
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
expect(decryptedMessage).toBeInstanceOf(Uint8Array);
|
|
308
|
+
});
|
|
@@ -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,
|
|
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,
|
|
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
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
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,
|
|
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
|
+
});
|
package/encryption/encryption.ts
CHANGED
|
@@ -8,7 +8,12 @@ import {
|
|
|
8
8
|
readPrivateKey,
|
|
9
9
|
} from 'openpgp';
|
|
10
10
|
import { ModelsPublicNoteEncryptionTypeEnum } from '../remote-api';
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
OrgNoteEncryption,
|
|
13
|
+
OrgNotePasswordEncryption,
|
|
14
|
+
WithDecryptionContent,
|
|
15
|
+
} from '../models/encryption';
|
|
16
|
+
import { OrgNoteGpgEncryption, WithEncryptionContent } from 'src/models';
|
|
12
17
|
|
|
13
18
|
export class IncorrectOrMissingPrivateKeyPasswordError extends Error {}
|
|
14
19
|
export class ImpossibleToDecryptWithProvidedKeysError extends Error {}
|
|
@@ -43,74 +48,84 @@ export const encryptViaPassword = withCustomErrors(_encryptViaPassword);
|
|
|
43
48
|
export const decryptViaPassword = withCustomErrors(_decryptViaPassword);
|
|
44
49
|
export const decryptViaKeys = withCustomErrors(_decryptViaKeys);
|
|
45
50
|
|
|
46
|
-
export const encrypt = async
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
51
|
+
export const encrypt = async <
|
|
52
|
+
T extends WithEncryptionContent<OrgNoteEncryption>,
|
|
53
|
+
>(
|
|
54
|
+
encryptionParams: T
|
|
55
|
+
): Promise<T['format'] extends 'binary' ? Uint8Array : string> => {
|
|
50
56
|
if (
|
|
51
57
|
!encryptionParams.type ||
|
|
52
58
|
encryptionParams.type === ModelsPublicNoteEncryptionTypeEnum.Disabled
|
|
53
59
|
) {
|
|
54
|
-
return
|
|
60
|
+
return encryptionParams.content as any;
|
|
55
61
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
|
|
63
|
+
const res = (encryptionParams.type ===
|
|
64
|
+
ModelsPublicNoteEncryptionTypeEnum.GpgKeys
|
|
65
|
+
? await encryptViaKeys(encryptionParams)
|
|
66
|
+
: await encryptViaPassword(encryptionParams)) as unknown as Promise<
|
|
67
|
+
T['format'] extends 'binary' ? Uint8Array : string
|
|
68
|
+
>;
|
|
69
|
+
|
|
70
|
+
return res;
|
|
64
71
|
};
|
|
65
72
|
|
|
66
|
-
export const decrypt = async
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
73
|
+
export const decrypt = async <
|
|
74
|
+
T extends WithDecryptionContent<OrgNoteEncryption>,
|
|
75
|
+
>(
|
|
76
|
+
decryptionParams: T
|
|
77
|
+
): Promise<T['format'] extends 'binary' ? Uint8Array : string> => {
|
|
70
78
|
if (
|
|
71
|
-
!
|
|
72
|
-
|
|
79
|
+
!decryptionParams.type ||
|
|
80
|
+
decryptionParams.type === ModelsPublicNoteEncryptionTypeEnum.Disabled
|
|
73
81
|
) {
|
|
74
|
-
return
|
|
82
|
+
return decryptionParams.content as any;
|
|
75
83
|
}
|
|
76
|
-
const decryptedNote =
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
: await decryptViaPassword(text, encryptionParams.password);
|
|
84
|
+
const decryptedNote = (decryptionParams.type ===
|
|
85
|
+
ModelsPublicNoteEncryptionTypeEnum.GpgKeys
|
|
86
|
+
? await decryptViaKeys(decryptionParams)
|
|
87
|
+
: await decryptViaPassword(decryptionParams)) as unknown as Promise<
|
|
88
|
+
T['format'] extends 'binary' ? Uint8Array : string
|
|
89
|
+
>;
|
|
90
|
+
|
|
84
91
|
return decryptedNote;
|
|
85
92
|
};
|
|
86
93
|
|
|
87
|
-
async function _encryptViaPassword
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
94
|
+
async function _encryptViaPassword<
|
|
95
|
+
T extends WithEncryptionContent<OrgNotePasswordEncryption>,
|
|
96
|
+
>({
|
|
97
|
+
content,
|
|
98
|
+
password,
|
|
99
|
+
format = 'binary',
|
|
100
|
+
}: T): Promise<T['format'] extends 'binary' ? Uint8Array : string> {
|
|
91
101
|
const message = await createMessage({
|
|
92
|
-
text,
|
|
102
|
+
text: content,
|
|
93
103
|
});
|
|
94
104
|
|
|
95
105
|
const encryptedMessage = await _encrypt({
|
|
96
106
|
message,
|
|
97
|
-
format:
|
|
107
|
+
format: format as any,
|
|
98
108
|
passwords: [password],
|
|
99
109
|
});
|
|
100
110
|
|
|
101
|
-
return encryptedMessage
|
|
111
|
+
return encryptedMessage as Promise<
|
|
112
|
+
T['format'] extends 'binary' ? Uint8Array : string
|
|
113
|
+
>;
|
|
102
114
|
}
|
|
103
115
|
|
|
104
|
-
async function _encryptViaKeys
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
116
|
+
export async function _encryptViaKeys<
|
|
117
|
+
T extends WithEncryptionContent<OrgNoteGpgEncryption>,
|
|
118
|
+
>({
|
|
119
|
+
content,
|
|
120
|
+
publicKey: armoredPublicKey,
|
|
121
|
+
privateKey: armoredPrivateKey,
|
|
122
|
+
privateKeyPassphrase,
|
|
123
|
+
format = 'binary',
|
|
124
|
+
}: T): Promise<T['format'] extends 'binary' ? Uint8Array : string> {
|
|
110
125
|
const publicKey = await readKey({ armoredKey: armoredPublicKey });
|
|
111
126
|
|
|
112
127
|
const message = await createMessage({
|
|
113
|
-
text,
|
|
128
|
+
text: content,
|
|
114
129
|
});
|
|
115
130
|
|
|
116
131
|
const encryptedPrivateKey = await readPrivateKey({
|
|
@@ -126,52 +141,73 @@ async function _encryptViaKeys(
|
|
|
126
141
|
|
|
127
142
|
const encryptedMessage = await _encrypt({
|
|
128
143
|
message,
|
|
129
|
-
format:
|
|
144
|
+
format: format as any,
|
|
130
145
|
encryptionKeys: publicKey,
|
|
131
146
|
signingKeys: privateKey,
|
|
132
147
|
});
|
|
133
148
|
|
|
134
|
-
return encryptedMessage
|
|
149
|
+
return encryptedMessage as Promise<
|
|
150
|
+
T['format'] extends 'binary' ? Uint8Array : string
|
|
151
|
+
>;
|
|
135
152
|
}
|
|
136
153
|
|
|
137
|
-
async function _decryptViaPassword
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
154
|
+
async function _decryptViaPassword<
|
|
155
|
+
T extends Omit<WithDecryptionContent<OrgNotePasswordEncryption>, 'type'>,
|
|
156
|
+
>({
|
|
157
|
+
content,
|
|
158
|
+
password,
|
|
159
|
+
format = 'utf8',
|
|
160
|
+
}: T): Promise<T['format'] extends 'binary' ? Uint8Array : string> {
|
|
161
|
+
const isArmoredContent = typeof content === 'string';
|
|
162
|
+
|
|
163
|
+
const message = await (isArmoredContent
|
|
164
|
+
? readMessage({ armoredMessage: content })
|
|
165
|
+
: readMessage({ binaryMessage: content }));
|
|
142
166
|
|
|
143
167
|
const { data: decryptedText } = await _decrypt({
|
|
144
168
|
message,
|
|
169
|
+
format,
|
|
145
170
|
passwords: password,
|
|
146
171
|
});
|
|
147
172
|
|
|
148
|
-
return decryptedText
|
|
173
|
+
return decryptedText as Promise<
|
|
174
|
+
T['format'] extends 'binary' ? Uint8Array : string
|
|
175
|
+
>;
|
|
149
176
|
}
|
|
150
177
|
|
|
151
|
-
async function _decryptViaKeys
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
178
|
+
async function _decryptViaKeys<
|
|
179
|
+
T extends Omit<WithDecryptionContent<OrgNoteGpgEncryption>, 'type'>,
|
|
180
|
+
>({
|
|
181
|
+
privateKey: armoredPrivateKey,
|
|
182
|
+
privateKeyPassphrase,
|
|
183
|
+
content,
|
|
184
|
+
format = 'utf8',
|
|
185
|
+
}: T): Promise<T['format'] extends 'binary' ? Uint8Array : string> {
|
|
156
186
|
const encryptedPrivateKey = await readPrivateKey({
|
|
157
187
|
armoredKey: armoredPrivateKey,
|
|
158
188
|
});
|
|
159
189
|
|
|
160
|
-
const privateKey =
|
|
190
|
+
const privateKey = privateKeyPassphrase
|
|
161
191
|
? await decryptKey({
|
|
162
192
|
privateKey: encryptedPrivateKey,
|
|
163
|
-
passphrase:
|
|
193
|
+
passphrase: privateKeyPassphrase,
|
|
164
194
|
})
|
|
165
195
|
: encryptedPrivateKey;
|
|
166
196
|
|
|
167
|
-
const
|
|
197
|
+
const isString = typeof content === 'string';
|
|
198
|
+
const message = await (isString
|
|
199
|
+
? readMessage({ armoredMessage: content })
|
|
200
|
+
: readMessage({ binaryMessage: content }));
|
|
168
201
|
|
|
169
202
|
const { data: decryptedText } = await _decrypt({
|
|
170
203
|
message,
|
|
204
|
+
format,
|
|
171
205
|
decryptionKeys: privateKey,
|
|
172
206
|
});
|
|
173
207
|
|
|
174
|
-
return decryptedText
|
|
208
|
+
return decryptedText as Promise<
|
|
209
|
+
T['format'] extends 'binary' ? Uint8Array : string
|
|
210
|
+
>;
|
|
175
211
|
}
|
|
176
212
|
|
|
177
213
|
function withCustomErrors<P extends unknown[], T>(
|
|
@@ -4,19 +4,23 @@ import {
|
|
|
4
4
|
} from '../remote-api';
|
|
5
5
|
|
|
6
6
|
import {
|
|
7
|
+
decrypt,
|
|
7
8
|
decryptViaKeys,
|
|
8
9
|
decryptViaPassword,
|
|
10
|
+
encrypt,
|
|
9
11
|
encryptViaKeys,
|
|
10
12
|
encryptViaPassword,
|
|
11
13
|
} from './encryption';
|
|
12
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
OrgNoteEncryption,
|
|
16
|
+
WithDecryptionContent,
|
|
17
|
+
WithEncryptionContent,
|
|
18
|
+
WithNoteDecryptionContent,
|
|
19
|
+
} from '../models/encryption';
|
|
13
20
|
import { parse, withMetaInfo } from 'org-mode-ast';
|
|
14
21
|
import { isGpgEncrypted } from '..';
|
|
15
22
|
|
|
16
|
-
export type NoteEncryptionType = `${ModelsPublicNote['encryptionType']}`;
|
|
17
|
-
|
|
18
23
|
export interface AbstractEncryptedNote {
|
|
19
|
-
encryptionType?: NoteEncryptionType;
|
|
20
24
|
encrypted?: boolean;
|
|
21
25
|
meta: {
|
|
22
26
|
[key: string]: any;
|
|
@@ -29,8 +33,7 @@ export type EncryptionResult<T> = Promise<[T, string]>;
|
|
|
29
33
|
// TODO: master change signature for encrypt notes without content
|
|
30
34
|
export async function encryptNote<T extends AbstractEncryptedNote>(
|
|
31
35
|
note: T,
|
|
32
|
-
|
|
33
|
-
encryptionParams: OrgNoteEncryption
|
|
36
|
+
encryptionParams: WithEncryptionContent<OrgNoteEncryption>
|
|
34
37
|
): EncryptionResult<T> {
|
|
35
38
|
note.encrypted = false;
|
|
36
39
|
if (
|
|
@@ -38,132 +41,47 @@ export async function encryptNote<T extends AbstractEncryptedNote>(
|
|
|
38
41
|
encryptionParams.type === ModelsPublicNoteEncryptionTypeEnum.Disabled ||
|
|
39
42
|
note.meta.published
|
|
40
43
|
) {
|
|
41
|
-
return [note,
|
|
44
|
+
return [note, encryptionParams.content];
|
|
42
45
|
}
|
|
43
46
|
|
|
44
47
|
note.meta = { id: note.meta.id, published: note.meta.published };
|
|
45
48
|
|
|
46
|
-
const
|
|
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);
|
|
49
|
+
const encryptedContent = await encrypt(encryptionParams);
|
|
55
50
|
|
|
56
|
-
encryptedNote
|
|
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
|
-
}
|
|
51
|
+
const encryptedNote = { ...note, encrypted: true };
|
|
73
52
|
|
|
74
|
-
|
|
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
|
-
];
|
|
53
|
+
return [encryptedNote, encryptedContent];
|
|
95
54
|
}
|
|
96
55
|
|
|
97
56
|
export async function decryptNote<T extends AbstractEncryptedNote>(
|
|
98
57
|
note: T,
|
|
99
|
-
|
|
100
|
-
encryptionParams: OrgNoteEncryption
|
|
58
|
+
encryptionParams: WithNoteDecryptionContent<OrgNoteEncryption>
|
|
101
59
|
): EncryptionResult<T> {
|
|
102
|
-
const isContentEncrypted = isGpgEncrypted(
|
|
60
|
+
const isContentEncrypted = isGpgEncrypted(encryptionParams.content);
|
|
103
61
|
if (
|
|
104
62
|
note.meta.published ||
|
|
105
|
-
!note.encryptionType ||
|
|
106
63
|
!encryptionParams.type ||
|
|
107
64
|
encryptionParams.type === ModelsPublicNoteEncryptionTypeEnum.Disabled ||
|
|
108
65
|
!isContentEncrypted
|
|
109
66
|
) {
|
|
110
67
|
note.encrypted = isContentEncrypted;
|
|
111
|
-
return [note,
|
|
68
|
+
return [note, encryptionParams.content];
|
|
112
69
|
}
|
|
113
70
|
note.encrypted = true;
|
|
114
|
-
const
|
|
115
|
-
encryptionParams
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
noteText,
|
|
119
|
-
encryptionParams.privateKey,
|
|
120
|
-
encryptionParams.privateKeyPassphrase
|
|
121
|
-
)
|
|
122
|
-
: await decryptNoteViaPassword(note, noteText, encryptionParams.password);
|
|
71
|
+
const decryptionParams = {
|
|
72
|
+
...encryptionParams,
|
|
73
|
+
format: 'utf8',
|
|
74
|
+
} as WithDecryptionContent<OrgNoteEncryption>;
|
|
123
75
|
|
|
76
|
+
const decryptedNoteText = await decrypt(decryptionParams);
|
|
124
77
|
const parsed = withMetaInfo(parse(decryptedNoteText));
|
|
125
78
|
|
|
126
79
|
return [
|
|
127
80
|
{
|
|
128
|
-
...
|
|
81
|
+
...note,
|
|
129
82
|
encrypted: false,
|
|
130
83
|
meta: parsed.meta,
|
|
131
84
|
},
|
|
132
85
|
decryptedNoteText,
|
|
133
86
|
];
|
|
134
87
|
}
|
|
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
|
-
}
|
package/models/encryption.ts
CHANGED
|
@@ -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