orgnote-api 0.12.2 → 0.12.3

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.
@@ -0,0 +1,346 @@
1
+ import { expect, test } from 'vitest';
2
+ import { decryptNote, encryptNote } from '../note-encryption';
3
+ import { Note } from '../../models';
4
+ import {
5
+ armoredPublicKey,
6
+ armoredPrivateKey,
7
+ privateKeyPassphrase,
8
+ } from './encryption-keys';
9
+
10
+ test('Should encrypt note content via password', async () => {
11
+ const content = `#+ID: qweqwe
12
+
13
+ #+TITLE: Hello worlld
14
+
15
+ * Hello?`;
16
+
17
+ const note: Note = {
18
+ id: 'id',
19
+ encryptionType: 'gpgPassword',
20
+ meta: {
21
+ title: 'My note title',
22
+ images: [],
23
+ published: false,
24
+ description: 'Awesome description',
25
+ },
26
+ content,
27
+ author: {
28
+ id: '1',
29
+ name: 'John Doe',
30
+ email: 'test@mail.com',
31
+ },
32
+ };
33
+
34
+ const encryptedNote = await encryptNote(note, {
35
+ type: 'gpgPassword',
36
+ password: '123',
37
+ });
38
+
39
+ expect(encryptedNote.content.startsWith('-----BEGIN PGP MESSAGE-----')).toBe(
40
+ true
41
+ );
42
+ delete encryptedNote.content;
43
+ expect(encryptedNote).toMatchSnapshot();
44
+ });
45
+
46
+ test('Should decrypt note content via password', async () => {
47
+ const note: Note = {
48
+ id: 'id',
49
+ encryptionType: 'gpgPassword',
50
+ meta: {
51
+ title: 'My note title',
52
+ images: [],
53
+ published: false,
54
+ description: 'Awesome description',
55
+ },
56
+ content: `-----BEGIN PGP MESSAGE-----
57
+
58
+ wy4ECQMI/CCaKMJEqy/gyROJeRgW9I738dDFBltFlxIjhxrN7nQ6gkX4GgX6
59
+ zt3v0mABvaBJA7corlU8su21TpPApOs/+DMWpVlbI3Zer7QfQK1fSBoSTbCR
60
+ 2k3g68Afayke2nLkDNkH62tdOPiTkx7bSlp1zL4uU440IM1g6dC72JkmtoTJ
61
+ 5Bjlwt4ZhxFsh+c=
62
+ =csID
63
+ -----END PGP MESSAGE-----`,
64
+ };
65
+
66
+ const decryptedNote = await decryptNote(note, {
67
+ type: 'gpgPassword',
68
+ password: '123',
69
+ });
70
+
71
+ expect(decryptedNote).toMatchSnapshot();
72
+ });
73
+
74
+ test('Should encrypt note via keys', async () => {
75
+ const content = `#+ID: qweqwe
76
+ #+TITLE: Hello worlld
77
+
78
+ * Hello?`;
79
+
80
+ const note: Note = {
81
+ id: 'id',
82
+ encryptionType: 'gpgKeys',
83
+ meta: {
84
+ title: 'My note title for encryption via keys',
85
+ images: [],
86
+ published: false,
87
+ description: 'Awesome description',
88
+ },
89
+ content,
90
+ author: {
91
+ id: '1',
92
+ name: 'John Doe',
93
+ email: 'test@mail.com',
94
+ },
95
+ };
96
+
97
+ const encryptedNote = await encryptNote(note, {
98
+ type: 'gpgKeys',
99
+ publicKey: armoredPublicKey,
100
+ privateKey: armoredPrivateKey,
101
+ privateKeyPassphrase,
102
+ });
103
+
104
+ expect(encryptedNote.content.startsWith('-----BEGIN PGP MESSAGE-----')).toBe(
105
+ true
106
+ );
107
+ delete encryptedNote.content;
108
+ expect(encryptedNote).toMatchSnapshot();
109
+ });
110
+
111
+ test('Should decrypt note via provided keys', async () => {
112
+ const note: Note = {
113
+ id: 'id',
114
+ encryptionType: 'gpgKeys',
115
+ meta: {
116
+ title: 'My note title for decryption via keys',
117
+ images: [],
118
+ published: false,
119
+ description: 'Awesome description',
120
+ },
121
+ content: `-----BEGIN PGP MESSAGE-----
122
+
123
+ wcFMA/vryg+TTn0rAQ//TBFRjKmjRQoLhSrgeH+NbsZXbxvo7Ey4k+BQ9XA5
124
+ +CMpXH9uFUxsSaI5+McUSEt32VI17HRpXQDCL9nwaWqWOanMaRe0tXXhtox2
125
+ gfe2f/6zsge9ux+mXF2BG4z+V5T8XIOrfzxosVprdJHZHM3x7cW5USQ0t2i2
126
+ FiOUWxSZO1899J3yICpMvhDXvTLVZuKpSNQho5PyXSeZa83eN+uYkhgt9lsk
127
+ 0KW88Nr435S6n6mVw/zpitXIgEKpkqh46mhG+1W3aC0lYx6j9lHm3bjtdb4r
128
+ 2mtZbWKwfdBggEy8qEeiUeslvKd6uWtEccomzFgJkaqWVGknLmrBdHfztRIV
129
+ fbZhxHz+J3GFOIgXf/5+fv+zg0nTazgz1mDUfnTHw3+qcAyEJ0ADdyg9EZc+
130
+ bKbK0GwzMDPQeM+cCRDWUTiIa1ruyEETiwMdhWUDztF8XxY2o8jXPerZ0NhG
131
+ R8l+SvAdYQQXPfxEh9lA3thkyz/Vp72pW46lUeJHGSq/fS6KIdLHLP9Z2e1J
132
+ aCFpNMgyAN+BaXwnbLZfz6k5hV8awbRScSWQLEg69D9b287SFDPOYW7OZikn
133
+ CKXL7xyQ5LrWJZN9Z/UPGjy+PdEw1SBhyluW6DQ+Sz1j4K8USTLqY89EInDl
134
+ G7AxHGujR9UkUGyUvvc71XW7jEOogiDgn1ZMoj9Y58LSweUB8vfkY3VF84Fy
135
+ zGVvLFWnFbtnWuoQC4OOXv1F6ETdmEsSMEMWKzRLDGPyqNX7FhG3cejlEuiK
136
+ EsT5oQhz00RECmnR8mJkGmJhzWmmeoQvaucFqhTOZjvYl9ivuEMBZ2jtkdHn
137
+ R6UNcNZRpCbfnl7YoikqbGBgqDFYydFGHXKHDpYhcQYWJsMDUayzUiPtzmaE
138
+ tgfTgNNqgPxkLnWA99KYNU8DH+FwgaYBuw9dwdqwcjxSbZjHhCFGUfsqM+ik
139
+ O9gcoAwVO1usODlESU7OWuSF2tIv5DBG5rhlSyxBp4d4aWmaumTswAdojy2O
140
+ sM70ETbg0mC8niW9lNsgJp55oFmlksvzjUIit5rBEr55rtPcJSgakPpR2yvd
141
+ Q4XjybUmV0IdONMhk/OlqaBPtnA0RG+qTcm7oP1qH/m5zRA0ZplVQ5ylkQwr
142
+ LwGq5JQpJkgxxgLIrUbbtzYBShXSr5c1XXR0LIRiNgtb6s1s4mt+fbyExdJF
143
+ +ceuu+/xYrW/YTuEJpHxLiZ+aNPW5g5Y7Hbqu3hp3UL/kD44cc8JjZh18spX
144
+ p/ncojDhF2r2vhR+CndYcMkpGMV+t1pGKC8wlcFc7lb9GJASnqMGvhQmvIaG
145
+ gO/x7UjuTZSBW+kITHHZJDqYryKUv1j0CkHxIn9tWsYOpa1giOFtXX5v0AAM
146
+ AJR/s/beLlqwCsUdYnw1TkP/0u0ZK3RPio1nJ7S6ckPfsM7DqCWD8ILD8Cdr
147
+ cuzQrWaE30t5PXx53xBPO+6t5wKfDL35WHWG1Irmvz9UuT7tDS3IzwtF4ijF
148
+ PX6alTbxGnoHgZ4bG4J1wfpTNPppP1gJeVg67VqOypzdZi+SjofMWnFgRFmD
149
+ yEN8xpFUs7A9xryVZOosp9Sfe3IbBkO99sAQ7jV4EoMYk3/GKA==
150
+ =LjkG
151
+ -----END PGP MESSAGE-----`,
152
+ };
153
+
154
+ const decryptedNote = await decryptNote(note, {
155
+ type: 'gpgKeys',
156
+ publicKey: armoredPublicKey,
157
+ privateKey: armoredPrivateKey,
158
+ privateKeyPassphrase,
159
+ });
160
+
161
+ expect(decryptedNote).toMatchSnapshot();
162
+ });
163
+
164
+ test('Should not encrypt public note', async () => {
165
+ const content = `#+ID: qweqwe
166
+ #+TITLE: Hello worlld
167
+
168
+ * Hello?`;
169
+
170
+ const note: Note = {
171
+ id: 'id',
172
+ encryptionType: 'gpgPassword',
173
+ meta: {
174
+ title: 'My note title',
175
+ images: [],
176
+ published: true,
177
+ description: 'Awesome description',
178
+ },
179
+ content,
180
+ author: {
181
+ id: '1',
182
+ name: 'John Doe',
183
+ email: 'test@mail.com',
184
+ },
185
+ };
186
+
187
+ const encryptedNote = await encryptNote(note, {
188
+ type: 'gpgPassword',
189
+ password: '123',
190
+ });
191
+
192
+ expect(encryptedNote.content.startsWith('-----BEGIN PGP MESSAGE-----')).toBe(
193
+ false
194
+ );
195
+ expect(encryptedNote).toMatchSnapshot();
196
+ });
197
+
198
+ test('Should encrypt note with empty encrypted property', async () => {
199
+ const content = `#+ID: qweqwe
200
+ #+TITLE: Hello worlld
201
+
202
+ * Hello?`;
203
+
204
+ const note: Note = {
205
+ id: 'id',
206
+ meta: {
207
+ title: 'My note title',
208
+ images: [],
209
+ published: false,
210
+ description: 'Awesome description',
211
+ },
212
+ content,
213
+ author: {
214
+ id: '1',
215
+ name: 'John Doe',
216
+ email: 'test@mail.com',
217
+ },
218
+ };
219
+
220
+ const encryptedNote = await encryptNote(note, {
221
+ type: 'gpgPassword',
222
+ password: '123',
223
+ });
224
+
225
+ expect(encryptedNote.content.startsWith('-----BEGIN PGP MESSAGE-----')).toBe(
226
+ true
227
+ );
228
+
229
+ delete encryptedNote.content;
230
+ expect(encryptedNote).toMatchSnapshot();
231
+ });
232
+
233
+ test('Should not decrypt note without provided encrypted type', async () => {
234
+ const content = `#+ID: qweqwe
235
+ #+TITLE: Hello worlld
236
+
237
+ * Hello?`;
238
+ const note: Note = {
239
+ id: 'id',
240
+ meta: {
241
+ title: 'My note title',
242
+ images: [],
243
+ published: false,
244
+ description: 'Awesome description',
245
+ },
246
+ encrypted: undefined,
247
+ content,
248
+ author: {
249
+ id: '1',
250
+ name: 'John Doe',
251
+ email: 'test@mail.com',
252
+ },
253
+ };
254
+
255
+ const decryptedNote = await decryptNote(note, {
256
+ type: 'gpgPassword',
257
+ password: '123',
258
+ });
259
+
260
+ expect(decryptedNote).toMatchSnapshot();
261
+ });
262
+
263
+ test('Should decrypt note and note meta', async () => {
264
+ const meta = {
265
+ title: 'My note title',
266
+ images: ['./image1.png'],
267
+ published: false,
268
+ description: 'Awesome description',
269
+ fileTags: ['tag1', 'tag2'],
270
+ };
271
+ const note: Note = {
272
+ id: 'id',
273
+ meta: { ...meta },
274
+ encryptionType: 'gpgPassword',
275
+ content: `#+TITLE: My note title
276
+ #+DESCRIPTION: Awesome description
277
+ #+PUBLISHED: false
278
+ #+FILETAGS: :tag1:tag2:
279
+
280
+ [[./image1.png]]
281
+
282
+ Hello world`,
283
+ };
284
+
285
+ const encryptedNote = await encryptNote(note, {
286
+ type: 'gpgPassword',
287
+ password: '123',
288
+ });
289
+
290
+ const decryptedNote = await decryptNote(encryptedNote, {
291
+ type: 'gpgPassword',
292
+ password: '123',
293
+ });
294
+
295
+ expect(meta).toEqual(decryptedNote.meta);
296
+ });
297
+
298
+ test('Should set not encrypted status when params type does not provided', async () => {
299
+ const note: Note = {
300
+ id: 'id',
301
+ encryptionType: 'gpgKeys',
302
+ meta: {
303
+ title: 'My note title for decryption via keys',
304
+ images: [],
305
+ published: false,
306
+ description: 'Awesome description',
307
+ },
308
+ content: `-----BEGIN PGP MESSAGE-----
309
+
310
+ wcFMA/vryg+TTn0rAQ//TBFRjKmjRQoLhSrgeH+NbsZXbxvo7Ey4k+BQ9XA5
311
+ +CMpXH9uFUxsSaI5+McUSEt32VI17HRpXQDCL9nwaWqWOanMaRe0tXXhtox2
312
+ gfe2f/6zsge9ux+mXF2BG4z+V5T8XIOrfzxosVprdJHZHM3x7cW5USQ0t2i2
313
+ FiOUWxSZO1899J3yICpMvhDXvTLVZuKpSNQho5PyXSeZa83eN+uYkhgt9lsk
314
+ 0KW88Nr435S6n6mVw/zpitXIgEKpkqh46mhG+1W3aC0lYx6j9lHm3bjtdb4r
315
+ 2mtZbWKwfdBggEy8qEeiUeslvKd6uWtEccomzFgJkaqWVGknLmrBdHfztRIV
316
+ fbZhxHz+J3GFOIgXf/5+fv+zg0nTazgz1mDUfnTHw3+qcAyEJ0ADdyg9EZc+
317
+ bKbK0GwzMDPQeM+cCRDWUTiIa1ruyEETiwMdhWUDztF8XxY2o8jXPerZ0NhG
318
+ R8l+SvAdYQQXPfxEh9lA3thkyz/Vp72pW46lUeJHGSq/fS6KIdLHLP9Z2e1J
319
+ aCFpNMgyAN+BaXwnbLZfz6k5hV8awbRScSWQLEg69D9b287SFDPOYW7OZikn
320
+ CKXL7xyQ5LrWJZN9Z/UPGjy+PdEw1SBhyluW6DQ+Sz1j4K8USTLqY89EInDl
321
+ G7AxHGujR9UkUGyUvvc71XW7jEOogiDgn1ZMoj9Y58LSweUB8vfkY3VF84Fy
322
+ zGVvLFWnFbtnWuoQC4OOXv1F6ETdmEsSMEMWKzRLDGPyqNX7FhG3cejlEuiK
323
+ EsT5oQhz00RECmnR8mJkGmJhzWmmeoQvaucFqhTOZjvYl9ivuEMBZ2jtkdHn
324
+ R6UNcNZRpCbfnl7YoikqbGBgqDFYydFGHXKHDpYhcQYWJsMDUayzUiPtzmaE
325
+ tgfTgNNqgPxkLnWA99KYNU8DH+FwgaYBuw9dwdqwcjxSbZjHhCFGUfsqM+ik
326
+ O9gcoAwVO1usODlESU7OWuSF2tIv5DBG5rhlSyxBp4d4aWmaumTswAdojy2O
327
+ sM70ETbg0mC8niW9lNsgJp55oFmlksvzjUIit5rBEr55rtPcJSgakPpR2yvd
328
+ Q4XjybUmV0IdONMhk/OlqaBPtnA0RG+qTcm7oP1qH/m5zRA0ZplVQ5ylkQwr
329
+ LwGq5JQpJkgxxgLIrUbbtzYBShXSr5c1XXR0LIRiNgtb6s1s4mt+fbyExdJF
330
+ +ceuu+/xYrW/YTuEJpHxLiZ+aNPW5g5Y7Hbqu3hp3UL/kD44cc8JjZh18spX
331
+ p/ncojDhF2r2vhR+CndYcMkpGMV+t1pGKC8wlcFc7lb9GJASnqMGvhQmvIaG
332
+ gO/x7UjuTZSBW+kITHHZJDqYryKUv1j0CkHxIn9tWsYOpa1giOFtXX5v0AAM
333
+ AJR/s/beLlqwCsUdYnw1TkP/0u0ZK3RPio1nJ7S6ckPfsM7DqCWD8ILD8Cdr
334
+ cuzQrWaE30t5PXx53xBPO+6t5wKfDL35WHWG1Irmvz9UuT7tDS3IzwtF4ijF
335
+ PX6alTbxGnoHgZ4bG4J1wfpTNPppP1gJeVg67VqOypzdZi+SjofMWnFgRFmD
336
+ yEN8xpFUs7A9xryVZOosp9Sfe3IbBkO99sAQ7jV4EoMYk3/GKA==
337
+ =LjkG
338
+ -----END PGP MESSAGE-----`,
339
+ };
340
+
341
+ const decryptedNote = await decryptNote(note, {
342
+ type: 'disabled',
343
+ });
344
+
345
+ expect(decryptedNote).toMatchSnapshot();
346
+ });
@@ -0,0 +1,172 @@
1
+ import {
2
+ createMessage,
3
+ decrypt,
4
+ decryptKey,
5
+ encrypt,
6
+ readKey,
7
+ readMessage,
8
+ readPrivateKey,
9
+ } from 'openpgp';
10
+
11
+ export class IncorrectOrMissingPrivateKeyPasswordError extends Error {}
12
+ export class ImpossibleToDecryptWithProvidedKeysError extends Error {}
13
+ export class IncorrectEncryptionPasswordError extends Error {}
14
+ export class NoKeysProvidedError extends Error {}
15
+ export class NoPasswordProvidedError extends Error {}
16
+
17
+ const noPrivateKeyPassphraseProvidedErrorMsg =
18
+ 'Error: Signing key is not decrypted.';
19
+ const incorrectPrivateKeyPassphraseErrorMsg =
20
+ 'Error decrypting private key: Incorrect key passphrase';
21
+ const decryptionKeyIsNotDecryptedErrorMsg =
22
+ 'Error decrypting message: Decryption key is not decrypted.';
23
+ const corruptedPrivateKeyErrorMsg = 'Misformed armored text';
24
+
25
+ const decriptionFailedErrorMsg =
26
+ 'Error decrypting message: Session key decryption failed.';
27
+ const incorrectEncryptionPasswordErrorMsg =
28
+ 'Error decrypting message: Modification detected.';
29
+
30
+ const noSymmetricallyEncryptedSessionKeyErrorMsg =
31
+ 'Error decrypting message: No symmetrically encrypted session key packet found.';
32
+
33
+ const armoredTextNotTypePrivateKeyErrorMsg =
34
+ 'Armored text not of type private key';
35
+
36
+ const notPrivateKeyErrprMsg =
37
+ 'Error decrypting message: No public key encrypted session key packet found.';
38
+
39
+ export const encryptViaKeys = withCustomErrors(_encryptViaKeys);
40
+ export const encryptViaPassword = withCustomErrors(_encryptViaPassword);
41
+ export const decryptViaPassword = withCustomErrors(_decryptViaPassword);
42
+ export const decryptViaKeys = withCustomErrors(_decryptViaKeys);
43
+
44
+ async function _encryptViaPassword(
45
+ text: string,
46
+ password: string
47
+ ): Promise<string> {
48
+ const message = await createMessage({
49
+ text,
50
+ });
51
+
52
+ const encryptedMessage = await encrypt({
53
+ message,
54
+ format: 'armored',
55
+ passwords: [password],
56
+ });
57
+
58
+ return encryptedMessage.toString();
59
+ }
60
+
61
+ async function _encryptViaKeys(
62
+ text: string,
63
+ armoredPublicKey: string,
64
+ armoredPrivateKey: string,
65
+ privateKeyPassphrase?: string
66
+ ): Promise<string> {
67
+ const publicKey = await readKey({ armoredKey: armoredPublicKey });
68
+
69
+ const message = await createMessage({
70
+ text,
71
+ });
72
+
73
+ const encryptedPrivateKey = await readPrivateKey({
74
+ armoredKey: armoredPrivateKey,
75
+ });
76
+
77
+ const privateKey = privateKeyPassphrase
78
+ ? await decryptKey({
79
+ privateKey: encryptedPrivateKey,
80
+ passphrase: privateKeyPassphrase,
81
+ })
82
+ : encryptedPrivateKey;
83
+
84
+ const encryptedMessage = await encrypt({
85
+ message,
86
+ format: 'armored',
87
+ encryptionKeys: publicKey,
88
+ signingKeys: privateKey,
89
+ });
90
+
91
+ return encryptedMessage.toString();
92
+ }
93
+
94
+ async function _decryptViaPassword(
95
+ data: string,
96
+ password: string
97
+ ): Promise<string> {
98
+ const message = await readMessage({ armoredMessage: data });
99
+
100
+ const { data: decryptedText } = await decrypt({
101
+ message,
102
+ passwords: password,
103
+ });
104
+
105
+ return decryptedText.toString();
106
+ }
107
+
108
+ async function _decryptViaKeys(
109
+ data: string,
110
+ armoredPrivateKey: string,
111
+ privateKeyPassword?: string
112
+ ): Promise<string> {
113
+ const encryptedPrivateKey = await readPrivateKey({
114
+ armoredKey: armoredPrivateKey,
115
+ });
116
+
117
+ const privateKey = privateKeyPassword
118
+ ? await decryptKey({
119
+ privateKey: encryptedPrivateKey,
120
+ passphrase: privateKeyPassword,
121
+ })
122
+ : encryptedPrivateKey;
123
+
124
+ const message = await readMessage({ armoredMessage: data });
125
+
126
+ const { data: decryptedText } = await decrypt({
127
+ message,
128
+ decryptionKeys: privateKey,
129
+ });
130
+
131
+ return decryptedText.toString();
132
+ }
133
+
134
+ function withCustomErrors<P extends unknown[], T>(
135
+ fn: (...args: P) => Promise<T | never>
136
+ ) {
137
+ return async (...args: P): Promise<T> => {
138
+ try {
139
+ return await fn(...args);
140
+ } catch (e: unknown) {
141
+ if (!(e instanceof Error)) {
142
+ throw e;
143
+ }
144
+ if (
145
+ [
146
+ noPrivateKeyPassphraseProvidedErrorMsg,
147
+ incorrectPrivateKeyPassphraseErrorMsg,
148
+ corruptedPrivateKeyErrorMsg,
149
+ decryptionKeyIsNotDecryptedErrorMsg,
150
+ armoredTextNotTypePrivateKeyErrorMsg,
151
+ ].includes(e.message)
152
+ ) {
153
+ throw new IncorrectOrMissingPrivateKeyPasswordError(e.message);
154
+ }
155
+ if (e.message === decriptionFailedErrorMsg) {
156
+ throw new ImpossibleToDecryptWithProvidedKeysError(e.message);
157
+ }
158
+ if (e.message === incorrectEncryptionPasswordErrorMsg) {
159
+ throw new IncorrectEncryptionPasswordError();
160
+ }
161
+ if (e.message === noSymmetricallyEncryptedSessionKeyErrorMsg) {
162
+ throw new NoKeysProvidedError();
163
+ }
164
+
165
+ if (e.message === notPrivateKeyErrprMsg) {
166
+ throw new NoPasswordProvidedError();
167
+ }
168
+
169
+ throw e;
170
+ }
171
+ };
172
+ }
@@ -0,0 +1,2 @@
1
+ export * from './note-encryption';
2
+ export * from './encryption';
@@ -0,0 +1,148 @@
1
+ import {
2
+ ModelsPublicNote,
3
+ ModelsPublicNoteEncryptionTypeEnum,
4
+ } from '../remote-api';
5
+
6
+ import {
7
+ decryptViaKeys,
8
+ decryptViaPassword,
9
+ encryptViaKeys,
10
+ encryptViaPassword,
11
+ } from './encryption';
12
+ import { OrgNoteEncryption } from '../models/encryption';
13
+ import { parse, withMetaInfo } from 'org-mode-ast';
14
+ import { isGpgEncrypted } from '..';
15
+
16
+ export type NoteEncryptionType = `${ModelsPublicNote['encryptionType']}`;
17
+
18
+ export interface AbstractEncryptedNote {
19
+ content: string;
20
+ encryptionType?: NoteEncryptionType;
21
+ encrypted?: boolean;
22
+ meta: {
23
+ [key: string]: any;
24
+ published?: boolean;
25
+ };
26
+ }
27
+ export async function encryptNote<T extends AbstractEncryptedNote>(
28
+ note: T,
29
+ encryptionParams: OrgNoteEncryption
30
+ ): Promise<T> {
31
+ note.encrypted = false;
32
+ if (
33
+ !encryptionParams.type ||
34
+ encryptionParams.type === ModelsPublicNoteEncryptionTypeEnum.Disabled ||
35
+ note.meta.published
36
+ ) {
37
+ return note;
38
+ }
39
+
40
+ note.meta = { id: note.meta.id, published: note.meta.published };
41
+
42
+ const encryptedNote =
43
+ encryptionParams.type === ModelsPublicNoteEncryptionTypeEnum.GpgKeys
44
+ ? await encryptNoteViaKeys(
45
+ note,
46
+ encryptionParams.publicKey,
47
+ encryptionParams.privateKey,
48
+ encryptionParams.privateKeyPassphrase
49
+ )
50
+ : await encryptNoteViaPassword(note, encryptionParams.password);
51
+
52
+ encryptedNote.encrypted = true;
53
+ return encryptedNote;
54
+ }
55
+ export async function encryptNoteViaPassword<T extends AbstractEncryptedNote>(
56
+ note: T,
57
+ password: string
58
+ ): Promise<T> {
59
+ const content = await encryptViaPassword(note.content, password);
60
+ return {
61
+ ...note,
62
+ content,
63
+ encrypted: ModelsPublicNoteEncryptionTypeEnum.GpgPassword,
64
+ };
65
+ }
66
+
67
+ export async function encryptNoteViaKeys<T extends AbstractEncryptedNote>(
68
+ note: T,
69
+ publicKey: string,
70
+ privateKey: string,
71
+ privateKeyPassphrase?: string
72
+ ): Promise<T> {
73
+ const content = await encryptViaKeys(
74
+ note.content,
75
+ publicKey,
76
+ privateKey,
77
+ privateKeyPassphrase
78
+ );
79
+
80
+ return {
81
+ ...note,
82
+ content,
83
+ encrypted: ModelsPublicNoteEncryptionTypeEnum.GpgKeys,
84
+ };
85
+ }
86
+
87
+ export async function decryptNote<T extends AbstractEncryptedNote>(
88
+ note: T,
89
+ encryptionParams: OrgNoteEncryption
90
+ ): Promise<T> {
91
+ const isContentEncrypted = isGpgEncrypted(note.content);
92
+ if (
93
+ note.meta.published ||
94
+ !note.encryptionType ||
95
+ !encryptionParams.type ||
96
+ encryptionParams.type === ModelsPublicNoteEncryptionTypeEnum.Disabled ||
97
+ !isContentEncrypted
98
+ ) {
99
+ note.encrypted = isContentEncrypted;
100
+ return note;
101
+ }
102
+ note.encrypted = true;
103
+ const decryptedNote =
104
+ encryptionParams.type === ModelsPublicNoteEncryptionTypeEnum.GpgKeys
105
+ ? await decryptNoteViaKeys(
106
+ note,
107
+ encryptionParams.privateKey,
108
+ encryptionParams.privateKeyPassphrase
109
+ )
110
+ : await decryptNoteViaPassword(note, encryptionParams.password);
111
+
112
+ const parsed = withMetaInfo(parse(decryptedNote.content));
113
+
114
+ return {
115
+ ...decryptedNote,
116
+ encrypted: false,
117
+ meta: parsed.meta,
118
+ };
119
+ }
120
+
121
+ export async function decryptNoteViaPassword<T extends AbstractEncryptedNote>(
122
+ note: T,
123
+ password: string
124
+ ): Promise<T> {
125
+ const content = await decryptViaPassword(note.content, password);
126
+ return {
127
+ ...note,
128
+ content,
129
+ encrypted: ModelsPublicNoteEncryptionTypeEnum.GpgPassword,
130
+ };
131
+ }
132
+
133
+ export async function decryptNoteViaKeys<T extends AbstractEncryptedNote>(
134
+ note: T,
135
+ privateKey: string,
136
+ privateKeyPassphrase?: string
137
+ ): Promise<T> {
138
+ const content = await decryptViaKeys(
139
+ note.content,
140
+ privateKey,
141
+ privateKeyPassphrase
142
+ );
143
+ return {
144
+ ...note,
145
+ content,
146
+ encrypted: ModelsPublicNoteEncryptionTypeEnum.GpgKeys,
147
+ };
148
+ }
package/files-api.ts ADDED
@@ -0,0 +1,25 @@
1
+ import { Axios } from 'axios';
2
+ import { Stream } from 'stream';
3
+
4
+ // NOTE: patch cause of incorrect generated api (form-data and swaggo)
5
+ export const initFilesApi = (axiosInstance: Axios) => {
6
+ return {
7
+ uploadFile: async (file: File) => {
8
+ const formData = new FormData();
9
+ formData.append('files', file);
10
+ const response = await axiosInstance.post('/files/upload', formData, {
11
+ headers: {
12
+ 'Content-Type': 'multipart/form-data',
13
+ },
14
+ });
15
+ return response.data;
16
+ },
17
+ downloadFile: async (relativeFilePath: string): Promise<Stream> => {
18
+ const downloadedFilePath = `/media/${relativeFilePath}`;
19
+ const stream = await axiosInstance
20
+ .get(downloadedFilePath, { responseType: 'stream' })
21
+ .then((r) => r.data);
22
+ return stream;
23
+ },
24
+ } as const;
25
+ };
package/index.ts ADDED
@@ -0,0 +1,7 @@
1
+ export * from './api';
2
+ export * from './models';
3
+ import type * as ast from 'org-mode-ast';
4
+ export * from './encryption';
5
+ export * from './tools';
6
+ export * from './files-api';
7
+ export { ast };