Compare commits

...

354 Commits

Author SHA1 Message Date
6f8ec5dee5 Develop generating doc password 2025-12-29 16:14:52 +03:00
79f14203dd Fix for easy copy/paste 2025-12-28 17:34:37 +03:00
e4800b8c54 Develop export/import and change password test variant 2025-12-28 17:20:05 +03:00
b8fda7871c Fix encrypt and decrypt with asymmetric key 2025-12-28 00:57:46 +03:00
9a2ad514db Some fixes for generating and getting public key 2025-12-27 23:48:42 +03:00
ce3fdfdf8a Develop crypto library 2025-12-26 20:37:44 +03:00
672c629fdf Develop crypto library 2025-12-25 23:12:54 +03:00
68447041f3 Add getKeyByPublicKey method 2025-12-24 19:29:52 +03:00
43b0ecfa19 Develop example 2025-12-24 19:29:23 +03:00
ff6a201f78 Develop crypto library 2025-12-23 19:43:49 +03:00
e10c0b73ca Develop crypto library 2025-12-22 20:27:05 +03:00
4a51b18279 Develop crypto library 2025-12-19 19:38:56 +03:00
ee56819e63 Develop crypto library 2025-12-18 19:20:03 +03:00
d6490a1671 Develop crypto library 2025-12-17 19:27:43 +03:00
2138e38d00 Develop crypto library 2025-12-15 19:41:31 +03:00
9f6e3be634 Develop crypto library 2025-12-15 01:01:44 +03:00
71f648c694 Develop crypto library 2025-12-11 19:11:33 +03:00
3f2ad2dfd7 Develop crypto library 2025-12-10 20:33:08 +03:00
4e28069ec9 Develop crypto library 2025-12-09 19:38:16 +03:00
615a73e7eb Develop extension 2025-12-08 20:10:17 +03:00
01786f307c Merge branch 'develop' of git.onlyoffice.com:ONLYOFFICE/core into feature/extensionCrypto 2025-12-05 15:00:34 +03:00
d1d94f481d . 2025-12-04 18:49:57 +03:00
82eb921f05 Merge pull request 'fix bug #78953' (#556) from fix/bug78953 into develop
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/core/pulls/556
2025-12-04 15:22:13 +00:00
84847f1e74 fix bug #78953 2025-12-04 21:19:39 +06:00
8391667147 Merge pull request 'Fix bug #48033' (#554) from fix/rtf into develop
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/core/pulls/554
2025-12-03 14:26:26 +00:00
39da47bc21 Fix bug #48033 2025-12-03 12:57:51 +03:00
3a201b8b28 Merge pull request 'fix bug #78778' (#553) from fix/bug78778 into develop
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/core/pulls/553
2025-12-02 14:04:25 +00:00
bbfbe4a149 Merge remote-tracking branch 'origin/fix/bug-78854' into develop 2025-12-02 16:28:20 +03:00
0c1c57ccb3 Fix bug 78854 2025-12-02 16:27:25 +03:00
7a3464b985 Fix test 2025-12-02 12:56:54 +03:00
49924e23ac AcroForm at the beginning 2025-12-02 12:56:07 +03:00
1eaac39e48 . 2025-12-01 22:34:28 +03:00
7624e24027 Merge remote-tracking branch 'origin/master' into develop 2025-12-01 21:53:15 +03:00
44ffa4b72e For bug 78854 2025-12-01 19:59:30 +03:00
10bdf2703a Merge pull request 'fix/bug69510' (#552) from fix/bug69510 into develop
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/core/pulls/552
2025-12-01 16:09:59 +00:00
c488384dbc fix/bug69510
fix bug #69510
2025-12-01 18:57:08 +03:00
b1b3e1fb7c Merge branch release/v9.2.0 into master 2025-12-01 07:25:12 +00:00
d78487e0f5 . 2025-11-29 12:25:03 +03:00
5069b68247 fix build 2025-11-28 20:46:03 +03:00
31433e20de Fix year detection on windows 2025-11-28 19:55:26 +03:00
86d0d2113e . 2025-11-28 17:30:28 +03:00
8f2b4e4153 Merge remote-tracking branch 'origin/feature/add-xls-writing' into develop 2025-11-28 15:03:05 +03:00
0be867c47d for bug #78766 2025-11-28 15:02:03 +03:00
78aae7e9d0 Merge pull request 'fix/bug76076' (#551) from fix/bug76076 into develop
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/core/pulls/551
2025-11-28 11:58:23 +00:00
10e63543dc Merge pull request 'fix bug #77811' (#550) from fix/bug77811 into develop
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/core/pulls/550
2025-11-28 11:57:22 +00:00
900cf01902 Merge pull request 'fix bug #78487' (#549) from fix/bug78487 into develop
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/core/pulls/549
2025-11-28 11:56:50 +00:00
f6a52876ce Fix bug 78801 2025-11-27 18:26:36 +03:00
45ad566eb1 Merge pull request 'Fix bug #75486' (#548) from fix/rtf into develop
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/core/pulls/548
2025-11-27 15:09:08 +00:00
5bbea51848 Fix bug #75486 2025-11-27 18:07:12 +03:00
28a1828000 fix bug #78778 2025-11-27 17:43:59 +06:00
816430e0e2 Generate doctrenderer embed 2025-11-27 13:40:37 +03:00
29a29cc818 Fix bug 78786 2025-11-27 13:37:05 +03:00
bf66c1d9c0 fix bug #78766 2025-11-27 11:39:26 +03:00
2a3982a884 Merge pull request 'Fix bug #69318' (#546) from fix/rtf into develop
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/core/pulls/546
2025-11-27 08:12:46 +00:00
b5fb8a34dc fix shared formulas conversion 2025-11-26 19:54:45 +06:00
11f0c937f4 Fix bug #69318 2025-11-26 16:28:07 +03:00
5e435d322f Merge branch 'develop' into feature/add-xls-writing 2025-11-26 17:03:08 +06:00
842d17f79e Merge pull request 'fix/bug37832' (#543) from fix/bug37832 into develop
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/core/pulls/543
2025-11-25 13:55:07 +00:00
d48a28fe1d Fix Redact merge image&form 2025-11-25 16:42:16 +03:00
2a22c5e1f3 fix/bug37832
fix bug #37832
2025-11-25 15:30:06 +03:00
629a35213e Merge remote-tracking branch 'origin/release/v9.2.0' into develop 2025-11-24 22:30:18 +03:00
a056b2e4a9 Merge pull request 'Fix direction determination' (#540) from fix/boolean-op into develop
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/core/pulls/540
2025-11-24 14:46:42 +00:00
2dd35a7d81 Fix direction determination 2025-11-24 17:31:01 +03:00
080d89c8a0 Merge remote-tracking branch 'origin/fix/bug69510' into develop 2025-11-24 15:57:45 +03:00
1809f7f4c2 Merge remote-tracking branch 'origin/fix/pdf-redact' into develop 2025-11-24 15:16:17 +03:00
4bfd4f0a08 Fix Encrypt with Redact 2025-11-24 15:13:35 +03:00
3ef5651dfd fix/bug69510
fix bug #69510
2025-11-24 14:52:55 +03:00
8231809ef0 fix bug #78487 2025-11-24 16:42:46 +06:00
7f3d073d63 Fix hierarchy of heading levels 2025-11-24 13:12:55 +03:00
5f09e91944 . 2025-11-23 12:39:22 +03:00
f4359e0b7f no message 2025-11-22 17:25:10 +03:00
ca9cf4ee61 . 2025-11-21 16:58:09 +03:00
f52538f66a . 2025-11-21 15:52:56 +03:00
15359be125 fix bug #77811 2025-11-21 16:10:49 +06:00
fc2a12c6f2 Merge remote-tracking branch 'origin/fix/bug69510' into develop 2025-11-21 10:34:42 +03:00
42030372fe fix logging 2025-11-21 10:29:36 +03:00
bbf6c2d8e9 fix/bug69510
fix bug #69510
2025-11-20 23:42:25 +03:00
cb15cc18eb Merge pull request 'fix/bug69510' (#538) from fix/bug69510 into develop
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/core/pulls/538
2025-11-20 11:46:32 +00:00
389bf976a9 fix/bug69510
fix bug #69510
2025-11-20 14:41:10 +03:00
4d1b516cc9 Merge remote-tracking branch 'origin/feature/pdf-password' into develop 2025-11-20 13:28:08 +03:00
600a59c966 Fix Open with owner password 2025-11-20 13:11:37 +03:00
66b2f3c828 Fix bug 78602 2025-11-20 12:48:09 +03:00
64e077da19 For bug 76845 2025-11-20 12:08:43 +03:00
499fe52b8c Merge remote-tracking branch 'origin/release/v9.2.0' into develop 2025-11-20 11:31:17 +03:00
6f9c376040 Create CheckPerm 2025-11-20 10:41:43 +03:00
1e18352e77 Create CheckOwnerPassword 2025-11-19 18:23:23 +03:00
c3f4f32702 fix read alternative drawing 2025-11-19 18:17:33 +03:00
6df7a7e01e Merge pull request 'Fix bug #53908' (#534) from fix/rtf into develop
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/core/pulls/534
2025-11-19 13:54:00 +00:00
6167f23a08 Fix bug #53908 2025-11-19 15:36:42 +03:00
7c544729bc Fix drawForm 2025-11-19 13:23:51 +03:00
d60c102dbb fix xlst->xlsb conversion 2025-11-18 19:41:06 +06:00
d709598563 Fix SaveRGBAToStream 2025-11-18 10:32:38 +03:00
7afad1fe49 fix bug #76076 2025-11-14 21:27:49 +06:00
aa53d6302f Fix RedactOutputDev::drawImageMask 2025-11-14 17:09:22 +03:00
7f665b96a5 Create Image for InlineImg 2025-11-13 18:00:15 +03:00
8926c15908 fix numFmt conversion 2025-11-13 19:49:14 +06:00
033c45b7a0 . 2025-11-13 16:40:30 +03:00
16d75fe498 Merge branch 'develop' into feature/add-xls-writing 2025-11-13 15:02:17 +06:00
fe2e1568fa Merge pull request 'fix/bug51597' (#524) from fix/bug51597 into develop
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/core/pulls/524
2025-11-12 18:27:24 +00:00
7e057bab6e fix list fmla conversion 2025-11-12 19:31:42 +06:00
4bf8308bff Merge branch 'develop' into feature/add-xls-writing 2025-11-12 14:16:45 +06:00
6af3f2fe35 Do RedactOutputDev::drawImageMask 2025-11-11 17:05:02 +03:00
b61d8df484 fix ptgArea3d conversion 2025-11-11 16:25:20 +06:00
fc3748e516 for bug #40743 2025-11-11 11:26:46 +03:00
468dcd7ba4 Merge remote-tracking branch 'origin/release/v9.2.0' into develop 2025-11-11 10:21:53 +03:00
238cdc8084 Merge branch 'develop' into feature/add-xls-writing 2025-11-10 15:08:26 +06:00
580283ef45 Merge remote-tracking branch 'origin/fix/rtf' into develop 2025-11-07 16:50:47 +03:00
fd648a7dd3 Merge remote-tracking branch 'origin/release/v9.2.0' into fix/pdf-redact
# Conflicts:
#	PdfFile/SrcReader/Adaptors.cpp
2025-11-07 14:03:51 +03:00
4d4f3be717 Fix bug #77975 2025-11-07 11:32:31 +03:00
6e481f6a34 Merge pull request 'fix/bug51965' (#515) from fix/bug51965 into develop
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/core/pulls/515
2025-11-07 06:47:08 +00:00
2059e4bb95 fix/bug51965
fix bug #51965
2025-11-07 00:58:31 +03:00
6a5186c411 fix 2025-11-06 14:55:28 +03:00
b5ea9d68e2 fix defined names fmlas xls conversion 2025-11-06 16:24:04 +06:00
d9be0df8fb Fix data validations conversion 2025-11-06 15:00:38 +06:00
3cee4b0212 Merge pull request 'For bug 77757' (#511) from rtfbugs/fix into develop
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/core/pulls/511
2025-11-05 12:22:52 +00:00
cfb62d599d For bug 77757 2025-11-05 13:55:43 +03:00
919d117a1f Fix ptgList conversion 2025-11-05 16:14:58 +06:00
d4b289d0ca Fix RedactOutputDev::drawSoftMaskedImage 2025-11-05 12:58:48 +03:00
270e8e41dd fix ptg list xls conversion 2025-11-01 19:44:50 +06:00
751b82dc51 fix dxfs conversion 2025-11-01 13:09:43 +06:00
320e30c857 Do RedactOutputDev::drawSoftMaskedImage 2025-10-31 17:13:38 +03:00
a6898c8235 Merge branch 'develop' into feature/add-xls-writing 2025-10-31 13:58:33 +06:00
463ca05404 Do RedactOutputDev::drawImage 2025-10-30 18:44:06 +03:00
548cee436a Merge remote-tracking branch 'origin/hotfix/v9.2.0' into develop 2025-10-30 15:13:03 +03:00
b1a36d546b fix ptgName writing 2025-10-30 18:06:11 +06:00
07d3f371a2 Merge pull request 'fix/bug77123' (#506) from fix/bug77123 into develop
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/core/pulls/506
2025-10-30 11:02:46 +00:00
278cac8a61 Merge branch 'fix/bug77123' into fix/bug51965 2025-10-30 13:56:13 +03:00
07fd1e87d7 Merge branch 'develop' into fix/bug51965 2025-10-30 13:55:14 +03:00
817ee4dde0 fix/bug77123
fix bug #77123
2025-10-30 13:50:56 +03:00
d93bd27896 Do RedactOutputDev::drawImage 2025-10-29 18:05:39 +03:00
be56209baf Fix empty cells conversion 2025-10-29 20:10:34 +06:00
6a573d0da7 Merge branch 'develop' into feature/add-xls-writing 2025-10-29 16:12:17 +06:00
e936e330d9 Do RedactOutputDev::drawForm 2025-10-28 18:21:00 +03:00
bda95fc03d Fix column styles conversion 2025-10-28 20:04:27 +06:00
c0c0289ffb Merge remote-tracking branch 'origin/Rtf/fixbugs' into develop 2025-10-28 15:57:46 +03:00
5c110799a6 . 2025-10-28 15:51:41 +03:00
1b6c81407b Merge branch 'develop' of https://git.onlyoffice.com/ONLYOFFICE/core into develop 2025-10-28 15:46:25 +03:00
1e0d662838 Fix previous 2025-10-28 15:35:46 +03:00
ae2680c419 fix defined names formula conversion 2025-10-28 18:18:57 +06:00
1b61353b2e Merge branch release/v9.1.0 into develop 2025-10-28 11:58:11 +00:00
7777048790 Merge branch release/v9.1.0 into master 2025-10-28 11:58:09 +00:00
fd6c0907bd Merge pull request 'fix/bug77123' (#504) from fix/bug77123 into develop
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/core/pulls/504
2025-10-28 11:33:11 +00:00
2aef5daf12 fix/bug77123 2025-10-28 14:06:05 +03:00
317e21af6a Merge remote-tracking branch 'origin/hotfix/v9.2.0' into develop 2025-10-28 11:29:01 +03:00
4f6daaae67 fix/bug77123
fix correct receipt page parametrs
2025-10-28 10:51:52 +03:00
8203492999 Merge branch 'develop' into feature/add-xls-writing 2025-10-28 13:19:12 +06:00
910f453ce8 Do RedactOutputDev::drawForm 2025-10-27 19:17:36 +03:00
54fb5a7891 remove smart_ptr for IFileConteiner (rels) 2025-10-27 18:54:00 +03:00
93b96e5555 fix bug #77324 2025-10-27 18:53:09 +03:00
9e57f8c3b1 Improve txt 2025-10-27 17:47:58 +03:00
57221c0e32 fix/bug77123
fix bug when the tabs were longer than available width
2025-10-27 16:27:48 +03:00
76b7099a37 Fix merged cells conversion 2025-10-27 19:04:55 +06:00
85f428fda6 fix formula conversion 2025-10-27 16:49:25 +06:00
d97a62442f Improve txt file writer 2025-10-27 13:40:48 +03:00
41fb12d58b Merge branch 'develop' into feature/add-xls-writing 2025-10-27 13:36:21 +06:00
ed0811d8ab For bug #50842 2025-10-25 11:52:35 +03:00
84cc97f035 Merge remote-tracking branch 'origin/hotfix/v9.2.0' into develop 2025-10-25 11:41:47 +03:00
984807d611 fix pivot cache id conversion 2025-10-24 19:23:02 +06:00
2796fbed8b Optimization read drawSoftMaskedImage 2025-10-24 12:10:33 +03:00
9ccbb25acd Improve txt file writer 2025-10-23 17:48:08 +03:00
954d86ed0f fix sxdb conversion 2025-10-23 20:01:28 +06:00
47e0a0c9e7 Improve txt file reader 2025-10-22 12:37:03 +03:00
2d7c5ec2df fix defined names conversion 2025-10-21 19:03:16 +06:00
38079e8692 comment unfinished functionality 2025-10-20 16:01:45 +06:00
ac75675367 optimized theme colors conversion 2025-10-20 15:41:44 +06:00
a0fc634f5f Merge branch 'develop' into feature/add-xls-writing 2025-10-20 14:03:42 +06:00
8d19851865 Change html language 2025-10-17 18:54:22 +03:00
2ebade4413 add theme colors conversion 2025-10-17 21:38:28 +06:00
5e9f99e960 For bug #50842 2025-10-17 11:59:06 +03:00
d98d3a211f Add select keys, sign and verify base64 data 2025-10-16 19:29:13 +03:00
a67935908a Merge remote-tracking branch 'origin/master' into develop 2025-10-16 18:57:38 +03:00
da1bc5d2d6 add theme colors registration 2025-10-16 20:33:32 +06:00
9d5388a7bf fix pivotCache id conversion 2025-10-15 20:38:36 +06:00
2cdb04656d Fix pivotfrt writing 2025-10-15 15:16:39 +06:00
3934c28eb8 Fix pivot table conversion 2025-10-14 21:17:58 +06:00
f6337bb12c add pivot table styles conversion 2025-10-14 18:30:59 +06:00
1d88830b38 fix/bug51597
fix bug when document convert from odt to docx and docx to odt and after this document cells width will smaller then before convertation.
2025-10-14 12:33:13 +03:00
9737038776 add addlStyles writing 2025-10-13 19:19:11 +06:00
915c3497e4 add pivotAddl writing 2025-10-13 16:26:19 +06:00
53c4f320f6 add pivot frt writing 2025-10-10 19:33:23 +06:00
1aec69965d add dateType pivot oper parsing 2025-10-10 15:15:22 +06:00
afdac778b0 Merge branch 'develop' into feature/add-xls-writing 2025-10-10 13:34:45 +06:00
fbc42a514f Fix pivots conversion 2025-10-09 19:46:21 +06:00
c567c9739c Merge remote-tracking branch 'origin/release/v9.1.0' into develop 2025-10-09 12:00:09 +03:00
686b719bff add pivot cache records conversion 2025-10-08 20:12:59 +06:00
f05fa7c0ee add pivotCache source conversion 2025-10-07 20:59:28 +06:00
0d646a32c4 add workbook pivotCache conversion 2025-10-07 17:09:10 +06:00
917c33e76d Fix pivot cache conversion 2025-10-06 21:08:26 +06:00
1937895a56 add sqlTypes conversion 2025-10-06 18:14:34 +06:00
01fbf07c9e add pivot field properties conversion 2025-10-06 16:56:13 +06:00
d208215814 Merge branch 'develop' into feature/add-xls-writing 2025-10-06 13:15:13 +06:00
c45c63f914 Merge pull request 'release/v9.1.0' (#474) from release/v9.1.0 into develop
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/core/pulls/474
2025-10-04 19:25:57 +00:00
5c5a18de0d add pivotCache properties conversion 2025-10-02 20:04:29 +06:00
9f24bda011 add pivotCache files conversion 2025-10-02 18:13:24 +06:00
fdb9eaa2a5 Add pivotCache stream writing 2025-10-02 15:41:11 +06:00
3e9b0ffbda add default params for SXEx 2025-10-02 14:30:16 +06:00
eb2ba042ef add pivotEx default writing 2025-10-01 21:22:55 +06:00
1111f421d9 Fix sxli conversion 2025-10-01 19:24:36 +06:00
e2bda52737 fix sxvd conversion 2025-10-01 17:38:08 +06:00
6c9c2cf538 fix pivot view header conversion 2025-10-01 17:13:56 +06:00
62d826d8c6 Merge branch 'develop' into feature/add-xls-writing 2025-10-01 14:05:17 +06:00
dfbdb869d7 add row&column items conversion 2025-09-30 15:04:03 +06:00
ed7a50855e Merge remote-tracking branch 'origin/release/v9.1.0' into develop 2025-09-29 21:58:01 +03:00
9f5b821c83 Develop extension 2025-09-29 19:17:47 +03:00
526a21da57 Merge branch 'develop' into feature/add-xls-writing 2025-09-29 17:06:24 +06:00
fb6bda209b add pivotIvd conversion 2025-09-29 17:04:36 +06:00
4b0f79a1ab add sxdi conversion 2025-09-29 16:00:11 +06:00
dbf46c8692 Add readme 2025-09-29 10:49:54 +03:00
d3e27eda98 Develop extension 2025-09-28 22:47:45 +03:00
e5953066a1 Develop extension 2025-09-26 20:10:03 +03:00
e5946892c9 add pivot field items conversion 2025-09-26 20:37:04 +06:00
d399027127 Add pivotField conversion 2025-09-26 19:31:23 +06:00
2e732ce62f add sxview conversion 2025-09-26 15:59:28 +06:00
c98942b871 Develop extension 2025-09-25 19:08:06 +03:00
44e6774c5a add pivot table writing 2025-09-25 18:37:33 +06:00
7ddb363d60 fix build 2025-09-25 13:19:47 +03:00
ecd333e238 Merge pull request 'feature/compound2' (#452) from feature/compound2 into develop
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/core/pulls/452
2025-09-25 09:27:18 +00:00
b377493ecb Merge branch 'develop' into feature/compound_any 2025-09-25 12:23:12 +03:00
afeeeab564 Merge remote-tracking branch 'origin/release/v9.1.0' into develop 2025-09-25 10:23:12 +03:00
e5caeed16c Develop extension 2025-09-24 19:17:24 +03:00
460abc0d55 fix xls color conversion 2025-09-24 20:48:11 +06:00
790c92c30b Develop extension 2025-09-23 20:27:18 +03:00
01b2aaedb2 add table styles conversion 2025-09-23 20:41:56 +06:00
580c896b72 fix table conversion 2025-09-23 18:13:47 +06:00
879007c270 Develop extension 2025-09-22 19:02:14 +03:00
03a1d9fa4c add table conversion 2025-09-22 19:37:14 +06:00
61d199a0c1 add list12 writing 2025-09-19 16:16:00 +06:00
24de9afbfb Develop extension 2025-09-18 19:21:54 +03:00
4ea31dcb00 Merge remote-tracking branch 'origin/release/v9.1.0' into develop 2025-09-18 19:07:44 +03:00
54a0c7f231 add feature11 writing 2025-09-18 20:36:54 +06:00
a4d60a1ae1 fix list parsed formula 2025-09-18 19:09:18 +06:00
b7b3e0dd65 add feat11field parts writing 2025-09-18 19:08:52 +06:00
c28a6bf1ea add feat11fieldData writing 2025-09-18 17:57:14 +06:00
9f24254cc7 add feat11 writing 2025-09-18 14:20:32 +06:00
8c4f2468a3 Develop extension 2025-09-17 19:17:55 +03:00
e105eca426 add tablestyle element conversion 2025-09-17 19:51:02 +06:00
02a923afb4 add table styles conversion 2025-09-17 18:06:07 +06:00
c7a0996a6c Fix condfmt colors conversion 2025-09-16 21:33:48 +06:00
49ca47d777 Add web extension polyfills 2025-09-16 16:58:05 +03:00
54a4c2b6fd Continue typing code 2025-09-16 16:52:47 +03:00
5f95ca7bfc Add gitignore 2025-09-16 12:49:09 +03:00
e66ecb52ad Add bundler 2025-09-16 12:34:49 +03:00
45e7b323ad Start rework extension 2025-09-15 19:42:21 +03:00
6d27231e15 add OfficeArtFOPT writing 2025-09-15 21:11:32 +06:00
a2a5ef8fcd add author writing to notes 2025-09-15 19:20:20 +06:00
1c877ebe59 add spgroup writing 2025-09-15 17:48:06 +06:00
f03248ca86 fix TextObject writing 2025-09-12 16:47:46 +06:00
a4005412a7 Merge branch 'develop' into feature/add-xls-writing 2025-09-12 13:37:30 +06:00
e50016259a add textObject processing 2025-09-11 21:38:36 +06:00
d5a6c935e5 add obj specifying for comment 2025-09-11 17:56:50 +06:00
aa3d4cb3ce add drawing preparation 2025-09-11 16:20:34 +06:00
73fa9b6aac Merge pull request 'fix bug 74748' (#439) from fix/bug-74748 into develop
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/core/pulls/439
2025-09-11 08:54:43 +00:00
c9a0d6e4e5 Merge branch hotfix/v9.0.4 into develop 2025-09-11 08:40:08 +00:00
b58ac033cf Add comments 2025-09-11 10:01:35 +03:00
130de28e4b Add comments conversion 2025-09-10 18:10:17 +06:00
cd53c06be3 fix bug 74748 2025-09-09 17:53:21 +03:00
122a54f510 add textObjectWriting 2025-09-09 18:45:39 +06:00
b425405744 add gboData writing 2025-09-08 17:36:02 +06:00
28ffd27fca add FtLbsData writing 2025-09-08 16:11:51 +06:00
9bc9d86dd6 add pict fmla writing 2025-09-08 14:43:35 +06:00
a1891b597f add pictFmla writing 2025-09-05 21:24:54 +06:00
bf9ce4f535 add ft macro writing 2025-09-05 19:10:52 +06:00
508d8f25db add obj writing 2025-09-05 18:09:11 +06:00
efbfcaed37 add OfficeArtSpContainer writing 2025-09-04 20:54:51 +06:00
d1fc31ac28 add OfficeArtFRITContainer writing 2025-09-04 18:50:50 +06:00
b8efe6c554 add fdg writing 2025-09-04 17:26:28 +06:00
13410f8467 add objects writing 2025-09-03 19:37:32 +06:00
3a389147dd add dbb writing 2025-09-03 15:13:04 +06:00
ba203f734d add fdb writing 2025-09-02 20:19:02 +06:00
758454747d add sxformula writing 2025-09-02 16:46:39 +06:00
bf175e92a3 add sxdb writing 2025-09-01 20:02:35 +06:00
0c9b5821e7 add pivotcache stream writing 2025-09-01 19:29:29 +06:00
98dae842ae Add data validations conversion 2025-09-01 18:26:48 +06:00
ff53c1b474 Add others template params for cf12 conversion 2025-08-25 21:12:27 +06:00
334f9602b4 add conditional formatting filter conversion 2025-08-22 20:06:20 +06:00
fed94358fe add multistate conversion 2025-08-22 17:44:53 +06:00
89b669e319 fix databar conversion 2025-08-22 15:16:06 +06:00
db213d3ae4 add cf databar conversion 2025-08-21 21:35:04 +06:00
79df81301f add colorScale cond fmt conversion 2025-08-21 18:52:07 +06:00
197bbf7027 Add aligment conversion to conditional formatting 2025-08-20 18:17:03 +06:00
a466592bc2 add protection conversion 2025-08-20 14:48:03 +06:00
4bce73d81d Add numfmt convesion to dxf 2025-08-20 14:06:50 +06:00
ed13e54d26 Add dxf border conversion 2025-08-19 19:18:01 +06:00
e371f7ccf1 add font condfmt conversion 2025-08-18 20:42:46 +06:00
14a0e4713c add fills conversion to conditional formatting 2025-08-18 17:03:07 +06:00
74b9a426c2 fix/bug-with break-columns
update comments
2025-08-18 13:27:29 +03:00
43c7e2c9a8 Add global info using in conversion 2025-08-15 20:55:34 +06:00
39b9c28607 fix dxfn conversion 2025-08-15 17:34:07 +06:00
6e57d7e4e7 fix cfParsed formula conversion 2025-08-14 20:40:20 +06:00
f831d9a22d add condFmt conversion 2025-08-14 17:56:01 +06:00
7f54430813 Add dxf conversion 2025-08-13 17:21:03 +06:00
ea42899b9e Merge branch 'develop' into feature/add-xls-writing 2025-08-13 13:20:11 +06:00
b420fd731f Add borders style conversion 2025-08-12 20:59:33 +06:00
dbbf4d04f9 Add blanc cell processing 2025-08-12 20:16:16 +06:00
62132c27bd add fills conversion 2025-08-11 17:09:43 +06:00
e4449d7aa9 Add font color conversion 2025-08-08 18:55:02 +06:00
cb304293b7 Add palette conversion 2025-08-08 14:20:56 +06:00
ffb62243a9 Merge branch 'develop' into feature/add-xls-writing 2025-08-08 13:27:43 +06:00
63a80580cc fix number value conversion 2025-08-07 20:04:19 +06:00
fed142690b Add data consolidation conversion 2025-08-07 15:13:09 +06:00
8d368ca91c Merge branch 'develop' into feature/add-xls-writing 2025-08-07 13:07:10 +06:00
2cc2434982 fix continue record writing 2025-08-06 20:27:16 +06:00
f5989b979a Fix autofilter record writing 2025-08-06 18:44:53 +06:00
62955d5f6e Add autofilter writing 2025-08-05 21:35:39 +06:00
9fc3fcabcb Fix sort data record writing 2025-08-04 19:01:27 +06:00
6af0b89c1d Add sort state conversion 2025-08-04 17:48:04 +06:00
c34b9e00e5 Merge branch 'develop' into feature/add-xls-writing 2025-08-04 13:14:17 +06:00
e715da8680 Add header and footer conversion 2025-08-01 18:33:49 +06:00
7a26c345c5 Fix margin conversion 2025-08-01 16:42:57 +06:00
2a6e76a2bc Add pagesetup conversion 2025-08-01 15:42:05 +06:00
adfc79938d Merge branch 'develop' into feature/add-xls-writing 2025-08-01 14:00:31 +06:00
c3ce1d2756 Fix hlink conversion 2025-07-31 19:14:09 +06:00
cf5208d6a5 Add hyperlinks conversion 2025-07-31 13:53:14 +06:00
56e6a0a3b8 Merge branch 'develop' into feature/add-xls-writing 2025-07-31 13:06:10 +06:00
0a7ad2f560 Add worksheet protection conversion 2025-07-30 17:25:53 +06:00
fede5921e1 add workbook protection conversion 2025-07-30 16:54:57 +06:00
897ea781b7 Fix font conversion 2025-07-30 15:45:59 +06:00
f95014f46f Add phonetic string conversion 2025-07-29 17:25:33 +06:00
92fae52a6d Fix rich string xls conversion 2025-07-28 21:52:30 +06:00
afb0f44af2 Add crun shared string conversion 2025-07-28 20:49:38 +06:00
af20b1f63d fix cell xf index writiong 2025-07-28 18:34:52 +06:00
c779654a58 Add cell styles conversion 2025-07-25 21:04:32 +06:00
d1c99891c6 Add xfs conversion 2025-07-25 18:12:27 +06:00
ffc94bf455 Add numFmts conversion 2025-07-25 15:27:53 +06:00
680c83853a Add fonts conversion 2025-07-25 14:44:08 +06:00
33e698242c Merge branch 'develop' into feature/add-xls-writing 2025-07-25 13:16:39 +06:00
e8ad643a0e Add bookviewsConversion 2025-07-24 21:24:07 +06:00
609e3bc158 Add worksheet view conversion 2025-07-24 20:50:37 +06:00
7e51dd143a Add colls & merged cells conversion 2025-07-24 15:02:36 +06:00
31d65dea7c Merge branch 'develop' into feature/add-xls-writing 2025-07-24 13:02:00 +06:00
89172a9047 add relsSorting 2025-07-23 20:45:04 +06:00
0103717241 add dimensions conversion 2025-07-23 20:44:54 +06:00
c012662402 Add array formula writing 2025-07-23 17:21:30 +06:00
00c3085a90 Merge branch 'develop' into feature/add-xls-writing 2025-07-22 17:37:35 +06:00
f1fa861c8a Add shared formula conversion 2025-07-22 17:35:57 +06:00
c37f96da2d Add formula conversion 2025-07-21 19:20:37 +06:00
89473c5ba0 Add simple shared strings conversion 2025-07-18 20:03:37 +06:00
07afc6e4c3 add simple cells conversion 2025-07-18 16:16:03 +06:00
34c34018a0 Merge branch 'develop' into feature/add-xls-writing 2025-07-18 14:48:55 +06:00
05dd636a1c Add cellType processing function 2025-07-17 21:36:00 +06:00
e6158043b9 add sheet data conversion 2025-07-17 18:42:22 +06:00
cfd1dcc3ee Add worksheets conversion 2025-07-17 17:14:12 +06:00
7a2944ce58 Add defined names conversion 2025-07-17 15:26:34 +06:00
8a11fa5aac Merge branch 'develop' into feature/add-xls-writing 2025-07-17 13:03:44 +06:00
aa2127b55f Add bundlesheet conversion 2025-07-16 20:28:40 +06:00
86a2d66d83 Add xlsx2xls conversion 2025-07-16 19:13:12 +06:00
3ceff2460c Developing... 2025-04-08 17:47:14 +03:00
c0c045f2f1 Fix build 2025-04-08 17:30:35 +03:00
5953eb8f08 Refactoring 2025-04-08 16:58:11 +03:00
6a6cfd7b5b Fix build module 2025-04-02 22:51:31 +03:00
1efde9d7e2 Developing 2025-04-02 17:04:37 +03:00
d6ed01e1df fix compound2 function 2023-09-04 12:25:28 +03:00
0fcf29eddc fix compound converter 2023-09-01 18:01:58 +03:00
474a500819 Add compound file to checker 2023-08-31 18:15:27 +03:00
581 changed files with 19873 additions and 1786 deletions

View File

@ -133,7 +133,7 @@ namespace NSOpenSSL
}
// rsa
bool RSA_GenerateKeys(unsigned char*& publicKey, unsigned char*& privateKey)
bool RSA_GenerateKeys(unsigned char*& publicKey, unsigned char*& privateKey, const int keyLen)
{
publicKey = NULL;
privateKey = NULL;
@ -142,7 +142,8 @@ namespace NSOpenSSL
BIGNUM *exponent = BN_new();
BN_set_word(exponent, RSA_F4);
int result = RSA_generate_multi_prime_key(rsa, 2048, 2, exponent, NULL);
int primes = (keyLen < 4096) ? 2 : 4;
int result = RSA_generate_multi_prime_key(rsa, keyLen, primes, exponent, NULL);
if (0 == result)
return false;
@ -370,6 +371,27 @@ namespace NSOpenSSL
// new algs
bool GenerateKeysByAlgs(const std::string& alg, std::string& publicKey, std::string& privateKey)
{
int nRsaKeyLen = 0;
if ("rsa2048" == alg)
nRsaKeyLen = 2048;
else if ("rsa4096" == alg)
nRsaKeyLen = 4096;
if (nRsaKeyLen > 0)
{
unsigned char* publicKeyPtr = NULL;
unsigned char* privateKeyPtr = NULL;
if (!RSA_GenerateKeys(publicKeyPtr, privateKeyPtr))
return false;
publicKey = std::string((char*)publicKeyPtr);
privateKey = std::string((char*)privateKeyPtr);
openssl_free(publicKeyPtr);
openssl_free(privateKeyPtr);
return true;
}
EVP_PKEY* pkey = NULL;
EVP_PKEY_CTX* pctx = NULL;
@ -453,7 +475,7 @@ namespace NSOpenSSL
return (1 == nResult) ? true : false;
}
CMemoryData Enrypt(const unsigned char* data, const int& data_len, const std::string& publicKey)
CMemoryData Encrypt(const unsigned char* data, const int& data_len, const std::string& publicKey, const bool& isLenToBuffer)
{
CMemoryData returnData;
@ -477,8 +499,19 @@ namespace NSOpenSSL
size_t ciphertextLen = 0;
EVP_PKEY_encrypt(ctx, NULL, &ciphertextLen, data, (size_t)data_len);
returnData.Alloc(ciphertextLen);
EVP_PKEY_encrypt(ctx, returnData.Data, &returnData.Size, data, (size_t)data_len);
if (isLenToBuffer)
{
returnData.Alloc(ciphertextLen + 4);
EVP_PKEY_encrypt(ctx, returnData.Data + 4, &returnData.Size, data, (size_t)data_len);
int nLen = (int)returnData.Size;
memcpy(returnData.Data, &nLen, 4);
}
else
{
returnData.Alloc(ciphertextLen);
EVP_PKEY_encrypt(ctx, returnData.Data, &returnData.Size, data, (size_t)data_len);
}
EVP_PKEY_free(pkey);
EVP_PKEY_CTX_free(ctx);
@ -486,7 +519,7 @@ namespace NSOpenSSL
return returnData;
}
CMemoryData Decrypt(const unsigned char* data, const int& data_len, const std::string& privateKey)
CMemoryData Decrypt(const unsigned char* data, const int& data_len, const std::string& privateKey, const bool& isLenToBuffer)
{
CMemoryData returnData;
@ -510,8 +543,19 @@ namespace NSOpenSSL
size_t ciphertextLen = 0;
EVP_PKEY_decrypt(ctx, NULL, &ciphertextLen, data, (size_t)data_len);
returnData.Alloc(ciphertextLen);
EVP_PKEY_decrypt(ctx, returnData.Data, &returnData.Size, data, (size_t)data_len);
if (isLenToBuffer)
{
returnData.Alloc(ciphertextLen + 4);
EVP_PKEY_decrypt(ctx, returnData.Data + 4, &returnData.Size, data, (size_t)data_len);
int nLen = (int)returnData.Size;
memcpy(returnData.Data, &nLen, 4);
}
else
{
returnData.Alloc(ciphertextLen);
EVP_PKEY_decrypt(ctx, returnData.Data, &returnData.Size, data, (size_t)data_len);
}
EVP_PKEY_free(pkey);
EVP_PKEY_CTX_free(ctx);

View File

@ -75,7 +75,7 @@ namespace NSOpenSSL
OPENSSL_DECL unsigned char* GetHash(const unsigned char* data, const unsigned int& size, const int& alg, unsigned int& len);
// rsa
OPENSSL_DECL bool RSA_GenerateKeys(unsigned char*& publicKey, unsigned char*& privateKey);
OPENSSL_DECL bool RSA_GenerateKeys(unsigned char*& publicKey, unsigned char*& privateKey, const int keyLen = 2048);
OPENSSL_DECL bool RSA_EncryptPublic(const unsigned char* publicKey, const unsigned char* data, const unsigned int& size, unsigned char*& data_crypt, unsigned int& data_crypt_len);
OPENSSL_DECL bool RSA_DecryptPrivate(const unsigned char* privateKey, const unsigned char* data, const unsigned int& size, unsigned char*& data_decrypt, unsigned int& data_decrypt_len);
@ -91,8 +91,8 @@ namespace NSOpenSSL
OPENSSL_DECL CMemoryData Sign(const unsigned char* data, const int& len, const std::string& privateKey);
OPENSSL_DECL bool Verify(const unsigned char* data, const int& data_len, const std::string& publicKey,
const unsigned char* signature, const int& signature_len);
OPENSSL_DECL CMemoryData Enrypt(const unsigned char* data, const int& data_len, const std::string& publicKey);
OPENSSL_DECL CMemoryData Decrypt(const unsigned char* data, const int& data_len, const std::string& privateKey);
OPENSSL_DECL CMemoryData Encrypt(const unsigned char* data, const int& data_len, const std::string& publicKey, const bool& isLenToBuffer = false);
OPENSSL_DECL CMemoryData Decrypt(const unsigned char* data, const int& data_len, const std::string& privateKey, const bool& isLenToBuffer = false);
// aes
OPENSSL_DECL int AES_GetKeySize(int type);

View File

@ -1,5 +0,0 @@
<<<<<<<
if((c >= 'a' && c <= 'z') || (c>= 'A' && c<= 'Z') || (c >= '0' && c<= '9')){
=======
if((c >= 'a' && c <= 'z') || (c>= 'A' && c<= 'Z') || (c >= '0' && c<= '9') || ('-' == c) || ('_' == c) || ('.' == c) || ('~' == c)){
>>>>>>>

View File

@ -74,6 +74,7 @@ public:
bool isDocFormatFile(const std::wstring& fileName);
bool isXlsFormatFile(const std::wstring& fileName);
bool isCompoundFile (POLE::Storage* storage);
bool isOleObjectFile(POLE::Storage* storage);
bool isDocFormatFile(POLE::Storage* storage);
bool isXlsFormatFile(POLE::Storage* storage);

View File

@ -552,6 +552,15 @@ bool COfficeFileFormatChecker::isPptFormatFile(POLE::Storage *storage)
return true;
}
bool COfficeFileFormatChecker::isCompoundFile(POLE::Storage* storage)
{
if (storage == NULL) return false;
if (storage->GetAllStreams(L"/").size() == 1) return true;
return false;
}
std::wstring COfficeFileFormatChecker::getDocumentID(const std::wstring &_fileName)
{
#if defined(_WIN32) || defined(_WIN32_WCE) || defined(_WIN64)
@ -749,6 +758,11 @@ bool COfficeFileFormatChecker::isOfficeFile(const std::wstring &_fileName)
nFileType = AVS_OFFICESTUDIO_FILE_OTHER_MS_VBAPROJECT;
return true;
}
else if (isCompoundFile(&storage))
{
nFileType = AVS_OFFICESTUDIO_FILE_OTHER_COMPOUND;
return true;
}
else if (isHwpFile(&storage))
{
nFileType = AVS_OFFICESTUDIO_FILE_DOCUMENT_HWP;

View File

@ -136,6 +136,7 @@
#define AVS_OFFICESTUDIO_FILE_OTHER_MS_MITCRYPTO AVS_OFFICESTUDIO_FILE_OTHER + 0x000b
#define AVS_OFFICESTUDIO_FILE_OTHER_MS_VBAPROJECT AVS_OFFICESTUDIO_FILE_OTHER + 0x000c
#define AVS_OFFICESTUDIO_FILE_OTHER_PACKAGE_IN_OLE AVS_OFFICESTUDIO_FILE_OTHER + 0x000d
#define AVS_OFFICESTUDIO_FILE_OTHER_COMPOUND AVS_OFFICESTUDIO_FILE_OTHER + 0x000e
#define AVS_OFFICESTUDIO_FILE_TEAMLAB 0x1000
#define AVS_OFFICESTUDIO_FILE_TEAMLAB_DOCY AVS_OFFICESTUDIO_FILE_TEAMLAB + 0x0001

View File

@ -33,8 +33,7 @@ OO_BUILD_BRANDING = $$(OO_BRANDING)
OO_DESTDIR_BUILD_OVERRIDE = $$(DESTDIR_BUILD_OVERRIDE)
win32 {
CURRENT_YEAR = $$system(wmic PATH Win32_LocalTime GET ^Year /FORMAT:VALUE | find \"=\")
CURRENT_YEAR = $$replace(CURRENT_YEAR, "Year=", "")
CURRENT_YEAR = $$system(powershell -NoLogo -NoProfile -Command "(Get-Date).Year")
CURRENT_YEAR = $$replace(CURRENT_YEAR, "\r", "")
CURRENT_YEAR = $$replace(CURRENT_YEAR, "\n", "")
CURRENT_YEAR = $$replace(CURRENT_YEAR, "\t", "")

View File

@ -10,6 +10,8 @@ import common
base.configure_common_apps()
python_binary = sys.executable
# fetch emsdk
command_prefix = "" if ("windows" == base.host_platform()) else "./"
if not base.is_dir("emsdk"):
@ -141,9 +143,9 @@ for param in argv:
if json_data["run_before"]:
base.print_info("before")
if base.is_file(work_dir + json_data["run_before"]):
base.cmd_in_dir(work_dir, "python", [json_data["run_before"]])
base.cmd_in_dir(work_dir, python_binary, [json_data["run_before"]])
else:
base.cmd_in_dir(work_dir, "python", ["-c", json_data["run_before"]])
base.cmd_in_dir(work_dir, python_binary, ["-c", json_data["run_before"]])
# remove previous version
common.clear_dir(work_dir + "/o")
@ -169,6 +171,6 @@ for param in argv:
if json_data["run_after"]:
base.print_info("after")
if base.is_file(work_dir + json_data["run_after"]):
base.cmd_in_dir(work_dir, "python", [json_data["run_after"]])
base.cmd_in_dir(work_dir, python_binary, [json_data["run_after"]])
else:
base.cmd_in_dir(work_dir, "python", ["-c", json_data["run_after"]])
base.cmd_in_dir(work_dir, python_binary, ["-c", json_data["run_after"]])

View File

@ -245,7 +245,18 @@ public:
return 0;
}
bool CheckOwnerPassword(const std::wstring& sPassword)
{
if (m_nType == 0)
return ((CPdfFile*)m_pFile)->CheckOwnerPassword(sPassword);
return true;
}
bool CheckPerm(int nPerm)
{
if (m_nType == 0)
return ((CPdfFile*)m_pFile)->CheckPerm(nPerm);
return true;
}
BYTE* GetInfo()
{
NSWasm::CData oRes;

View File

@ -30,6 +30,8 @@
-(JSValue*) SplitPages : (JSValue*)arrPageIndexes : (JSValue*)data;
-(JSValue*) MergePages : (JSValue*)data : (JSValue*)nMaxID : (JSValue*)sPrefixForm;
-(JSValue*) UnmergePages;
-(JSValue*) RedactPage : (JSValue*)nPageIndex : (JSValue*)arrRedactBox : (JSValue*)dataFiller;
-(JSValue*) UndoRedact;
@end
@interface CJSCDrawingFileEmbed : NSObject<IJSCDrawingFileEmbed, JSEmbedObjectProtocol>
@ -67,6 +69,8 @@ FUNCTION_WRAPPER_JS_1(FreeWasmData, FreeWasmData)
FUNCTION_WRAPPER_JS_2(SplitPages, SplitPages)
FUNCTION_WRAPPER_JS_3(MergePages, MergePages)
FUNCTION_WRAPPER_JS_0(UnmergePages, UnmergePages)
FUNCTION_WRAPPER_JS_3(RedactPage, RedactPage)
FUNCTION_WRAPPER_JS_0(UndoRedact, UndoRedact)
@end
class CDrawingFileEmbedAdapter : public CJSEmbedObjectAdapterJSC

View File

@ -67,7 +67,7 @@ namespace NSDrawingFileEmbed
NSV8Objects::Template_Set(result, "SplitPages", _SplitPages);
NSV8Objects::Template_Set(result, "MergePages", _MergePages);
NSV8Objects::Template_Set(result, "UnmergePages", _UnmergePages);
NSV8Objects::Template_Set(result, "RedactPage", _RedactPage);
NSV8Objects::Template_Set(result, "RedactPage", _RedactPage);
NSV8Objects::Template_Set(result, "UndoRedact", _UndoRedact);
return handle_scope.Escape(result);

View File

@ -886,17 +886,17 @@ namespace Aggplus
if (isCurve)
{
std::vector<PointD> points = GetPoints(idx, 4);
area = (points[3].Y - points[0].Y) * (points[1].X + points[2].X)
- (points[3].X - points[0].X) * (points[1].Y + points[2].Y)
+ points[1].Y * (points[0].X - points[2].X)
- points[1].X * (points[0].Y - points[2].Y)
+ points[3].Y * (points[2].X + points[0].X / 3.0)
- points[3].X * (points[2].Y + points[0].Y / 3.0);
area = 3.0 * (points[3].Y - points[0].Y) * (points[1].X + points[2].X)
- (points[3].X - points[0].X) * (points[1].Y + points[2].Y)
+ points[1].Y * (points[0].X - points[2].X)
- points[1].X * (points[0].Y - points[2].Y)
+ points[3].Y * (points[2].X + points[0].X / 3.0)
- points[3].X * (points[2].Y + points[0].Y / 3.0) / 20.0;
}
else
{
std::vector<PointD> points = GetPoints(idx, 2);
area = 4.0 * (points[1].Y * points[0].X - points[1].X * points[0].Y) / 3.0;
area = (points[1].Y * points[0].X - points[1].X * points[0].Y) / 2.0;
}
return area;

View File

@ -179,7 +179,6 @@ CHeadings::CHeading::CHeading()
nPage = 0;
dX = 0.0;
dY = 0.0;
pParent = NULL;
}
CHeadings::CHeading::~CHeading()
{
@ -196,35 +195,26 @@ CHeadings::~CHeadings()
const std::vector<CHeadings::CHeading*>& CHeadings::GetHeading() { return m_arrHeading; }
bool CHeadings::Read(NSOnlineOfficeBinToPdf::CBufferReader* pReader, IMetafileToRenderter* pCorrector)
{
int nPredLevel = 0, nHeaderLevel = 0;
std::vector<CHeading*>* arrHeading = &m_arrHeading;
CHeading* pParent = NULL;
std::vector<CHeading*> arrParentStack;
int nHeadings = pReader->ReadInt();
for (int i = 0; i < nHeadings; ++i)
{
int nLevel = pReader->ReadInt();
if (nLevel > nPredLevel && i > 0)
{
nHeaderLevel = nPredLevel;
pParent = arrHeading->back();
arrHeading = &pParent->arrHeading;
}
else if (nLevel < nPredLevel && nLevel <= nHeaderLevel)
{
nHeaderLevel = nLevel;
pParent = pParent ? pParent->pParent : NULL;
arrHeading = pParent ? &pParent->arrHeading : &m_arrHeading;
}
nPredLevel = nLevel;
CHeading* pHeading = new CHeading();
pHeading->nPage = pReader->ReadInt();
pHeading->dX = pReader->ReadDouble();
pHeading->dY = pReader->ReadDouble();
pHeading->wsTitle = pReader->ReadString();
pHeading->pParent = pParent;
arrHeading->push_back(pHeading);
while (arrParentStack.size() > nLevel)
arrParentStack.pop_back();
if (arrParentStack.empty())
m_arrHeading.push_back(pHeading);
else
arrParentStack.back()->arrHeading.push_back(pHeading);
arrParentStack.push_back(pHeading);
}
return true;
}

View File

@ -181,7 +181,6 @@ public:
int nPage;
double dX;
double dY;
CHeading* pParent;
std::vector<CHeading*> arrHeading;
CHeading();

View File

@ -56,6 +56,8 @@
"_UnmergePages",
"_RedactPage",
"_UndoRedact",
"_CheckOwnerPassword",
"_CheckPerm",
"_GetImageBase64",
"_GetImageBase64Len",
"_GetImageBase64Ptr",

View File

@ -145,6 +145,14 @@ CFile.prototype["isNeedPassword"] = function()
{
return this._isNeedPassword;
};
CFile.prototype["CheckOwnerPassword"] = function(password)
{
return this._CheckOwnerPassword(password);
};
CFile.prototype["CheckPerm"] = function(perm)
{
return this._CheckPerm(perm);
};
CFile.prototype["SplitPages"] = function(arrOriginIndex, arrayBufferChanges)
{
let ptr = this._SplitPages(arrOriginIndex, arrayBufferChanges);

View File

@ -146,6 +146,16 @@ CFile.prototype._UndoRedact = function()
return g_native_drawing_file["UndoRedact"]();
};
CFile.prototype._CheckOwnerPassword = function(password)
{
return true;
}
CFile.prototype._CheckPerm = function(perm)
{
return true;
}
// FONTS
CFile.prototype._isNeedCMap = function()
{

View File

@ -224,6 +224,29 @@ CFile.prototype._UndoRedact = function()
return Module["_UndoRedact"](this.nativeFile) == 1;
};
CFile.prototype._CheckOwnerPassword = function(password)
{
let passwordPtr = 0;
if (password)
{
let passwordBuf = password.toUtf8();
passwordPtr = Module["_malloc"](passwordBuf.length);
Module["HEAP8"].set(passwordBuf, passwordPtr);
}
let bRes = Module["_CheckOwnerPassword"](this.nativeFile, passwordPtr);
if (passwordPtr)
Module["_free"](passwordPtr);
return bRes == 1;
}
CFile.prototype._CheckPerm = function(perm)
{
return Module["_CheckPerm"](this.nativeFile, perm) == 1;
}
// FONTS
CFile.prototype._isNeedCMap = function()
{

View File

@ -191,6 +191,17 @@ WASM_EXPORT int UndoRedact(CDrawingFile* pFile)
{
return pFile->UndoRedact() ? 1 : 0;
}
WASM_EXPORT int CheckOwnerPassword(CDrawingFile* pFile, const char* password)
{
std::wstring sPassword = L"";
if (NULL != password)
sPassword = NSFile::CUtf8Converter::GetUnicodeStringFromUTF8((BYTE*)password, strlen(password));
return pFile->CheckOwnerPassword(sPassword) ? 1 : 0;
}
WASM_EXPORT int CheckPerm(CDrawingFile* pFile, int nPermFlag)
{
return pFile->CheckPerm(nPermFlag) ? 1 : 0;
}
WASM_EXPORT void* GetImageBase64(CDrawingFile* pFile, int rId)
{

View File

@ -1125,6 +1125,18 @@ int main(int argc, char* argv[])
}
}
// OWNER PASSWORD
if (false)
{
std::string sPassword = "gfhjkmgfhjkm";
std::cout << "CheckPerm 4 Edit " << CheckPerm(pGrFile, 4) << std::endl;
std::cout << "CheckPerm 4 Print " << CheckPerm(pGrFile, 3) << std::endl;
std::cout << "CheckOwnerPassword " << CheckOwnerPassword(pGrFile, sPassword.c_str()) << std::endl;
std::cout << "CheckPerm 4 Edit " << CheckPerm(pGrFile, 4) << std::endl;
std::cout << "CheckPerm 4 Print " << CheckPerm(pGrFile, 3) << std::endl;
}
BYTE* pColor = new BYTE[12] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
// REDACT
if (false)
@ -1164,7 +1176,7 @@ int main(int argc, char* argv[])
free(pInfo);
// LINKS
if (true && nPagesCount > 0)
if (false && nPagesCount > 0)
{
BYTE* pLinks = GetLinks(pGrFile, nTestPage);
nLength = READ_INT(pLinks);
@ -1200,7 +1212,7 @@ int main(int argc, char* argv[])
}
// STRUCTURE
if (true)
if (false)
{
BYTE* pStructure = GetStructure(pGrFile);
nLength = READ_INT(pStructure);

View File

@ -202,6 +202,19 @@ bool CImageFileFormatChecker::isWbcFile(BYTE* pBuffer,DWORD dwBytes)
return false;
}
//raster graphics file format developed by Google
bool CImageFileFormatChecker::isWebPFile(BYTE* pBuffer, DWORD dwBytes)
{
if (eFileType)return false;
if ((20 <= dwBytes) && ('R' == pBuffer[0] && 'I' == pBuffer[1] && 'F' == pBuffer[2] && 'F' == pBuffer[3]
//47 length + 12
&& 'W' == pBuffer[8] && 'E' == pBuffer[9] && 'B' == pBuffer[10] && 'P' == pBuffer[11])
&& 'V' == pBuffer[12] && 'P' == pBuffer[13] && '8' == pBuffer[14])
return true;
return false;
}
//webshot(wb ver 1) HEX 57 57 42 42 31 31 31 31
//webshot (wb ver 2) HEX 00 00 02 00 02 10 c9 00 02 00 c8 06 4c 00 02 00
bool CImageFileFormatChecker::isWbFile(BYTE* pBuffer,DWORD dwBytes)
@ -509,6 +522,10 @@ bool CImageFileFormatChecker::isImageFile(const std::wstring& fileName)
{
eFileType = _CXIMAGE_FORMAT_WB;
}
else if (isWebPFile(buffer, sizeRead))
{
eFileType = _CXIMAGE_FORMAT_WEBP;
}
else if (isPsdFile(buffer,sizeRead))
{
eFileType = _CXIMAGE_FORMAT_PSD;

View File

@ -64,6 +64,7 @@ enum __ENUM_CXIMAGE_FORMATS
_CXIMAGE_FORMAT_SVG = 24,
_CXIMAGE_FORMAT_PIC = 25,
_CXIMAGE_FORMAT_HEIF = 26,
_CXIMAGE_FORMAT_WEBP = 27
};
class GRAPHICS_DECL CImageFileFormatChecker
@ -96,6 +97,7 @@ public:
bool isTiffFile(BYTE* pBuffer,DWORD dwBytes);
bool isJpgFile(BYTE* pBuffer,DWORD dwBytes);
bool isWbFile(BYTE* pBuffer,DWORD dwBytes);
bool isWebPFile(BYTE* pBuffer, DWORD dwBytes);
bool isIcoFile(BYTE* pBuffer,DWORD dwBytes);
bool isRasFile(BYTE* pBuffer,DWORD dwBytes);

View File

@ -72,6 +72,11 @@ public:
}
public:
bool Sign(unsigned char* pData, unsigned int nSize, unsigned char*& pDataDst, unsigned int& nSizeDst)
{
return false;
}
std::string Sign(unsigned char* pData, unsigned int nSize)
{
NSOpenSSL::CMemoryData data = NSOpenSSL::Sign(pData, (int)nSize, m_pem_key);

View File

@ -0,0 +1,13 @@
import sys;
sys.path.append("../../../../../../build_tools/scripts");
import base;
base.replaceInFile("./deploy/engine.js", "__ATPOSTRUN__=[];", "__ATPOSTRUN__=[function(){window.cryptoJS.onLoad();}];");
base.replaceInFile("./deploy/engine.js", "__ATPOSTRUN__ = [];", "__ATPOSTRUN__=[function(){window.cryptoJS.onLoad();}];");
base.replaceInFile("./deploy/engine.js", "function getBinaryPromise()", "function getBinaryPromise2()");
base.replaceInFile("./deploy/engine_ie.js", "__ATPOSTRUN__=[];", "__ATPOSTRUN__=[function(){window.cryptoJS.onLoad();}];");
base.replaceInFile("./deploy/engine_ie.js", "__ATPOSTRUN__ = [];", "__ATPOSTRUN__=[function(){window.cryptoJS.onLoad();}];");
base.replaceInFile("./deploy/engine_ie.js", "function getBinaryPromise()", "function getBinaryPromise2()");
base.delete_file("./engine.wasm.js")

View File

@ -0,0 +1,7 @@
import sys
sys.path.append("../../../../../../build_tools/scripts")
import base
base.cmd_in_dir("./../3rdParty", sys.executable, ["openssl.py"])
base.copy_file("./extension/engine.wasm.js", "./engine.wasm.js")

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,56 @@
{
"name": "engine",
"res_folder": "./deploy",
"wasm": true,
"asm": true,
"embed_mem_file": true,
"run_before": "before.py",
"run_after": "after.py",
"base_js_content": "./engine.wasm.js",
"compiler_flags": [
"-O3",
"-Wno-unused-command-line-argument",
"-s ALLOW_MEMORY_GROWTH=1",
"-s FILESYSTEM=0",
"-s ENVIRONMENT='web'",
"-s ASSERTIONS",
"-s LLD_REPORT_UNDEFINED",
"-s TOTAL_MEMORY=4MB"
],
"exported_functions": [
"_malloc",
"_free",
"_Crypto_Malloc",
"_Crypto_Free",
"_Crypto_CreateKeys",
"_Crypto_Sign",
"_Crypto_ChangePassword",
"_Crypto_Decrypt",
"_Crypto_Encrypt"
],
"include_path": [
"./../3rdParty/openssl/include", "./../3rdParty/openssl"
],
"define": [
"__linux__", "_LINUX"
],
"compile_files_array": [
{
"name": "a",
"folder": "../../../../common/",
"files": ["Base64.cpp", "File.cpp"]
},
{
"name": "b",
"folder": "../../../../../Common/3dParty/openssl/common/",
"files": ["common_openssl.cpp"]
},
{
"name": "c",
"folder": "./",
"files": ["main.cpp"]
}
],
"sources": ["./../3rdParty/openssl/libcrypto.a"]
}

View File

@ -0,0 +1,48 @@
QT -= core gui
TARGET = wasm
TEMPLATE = app
CONFIG += console
CONFIG -= app_bundle
DEFINES += TEST_AS_EXECUTABLE
CORE_ROOT_DIR = $$PWD/../../../../..
PWD_ROOT_DIR = $$PWD
include($$CORE_ROOT_DIR/Common/base.pri)
DEFINES += KERNEL_NO_USE_DYNAMIC_LIBRARY
DEFINES += COMMON_OPENSSL_BUILDING_INTERNAL
SOURCES += \
$$CORE_ROOT_DIR/DesktopEditor/common/File.cpp \
$$CORE_ROOT_DIR/DesktopEditor/common/Base64.cpp
HEADERS += \
$$CORE_ROOT_DIR/DesktopEditor/xmlsec/src/include/Certificate.h \
$$CORE_ROOT_DIR/DesktopEditor/xmlsec/src/include/CertificateCommon.h
SOURCES += \
$$CORE_ROOT_DIR/DesktopEditor/xmlsec/src/src/CertificateCommon.cpp
DEFINES += SUPPORT_OFORM
HEADERS += $$CORE_ROOT_DIR/DesktopEditor/xmlsec/src/src/Certificate_oform.h
# OPENSSL
CONFIG += open_ssl_common
include($$CORE_ROOT_DIR/Common/3dParty/openssl/openssl.pri)
core_windows {
LIBS += -lcrypt32
LIBS += -lcryptui
LIBS += -lAdvapi32
LIBS += -lws2_32
LIBS += -lUser32
}
core_linux {
LIBS += -ldl
}
# WASM EXPORT
SOURCES += main.cpp

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,24 @@
function KeyStorage()
{
}
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
console.log("reseived in background:", message);
// Отображение всплывающего окна
chrome.action.openPopup();
// Посылаем событие обратно на страницу
if (sender.tab) {
chrome.scripting.executeScript({
target: { tabId: sender.tab.id },
func: (msg) => {
document.dispatchEvent(new CustomEvent("customEventFromExtension", { detail: msg }));
},
args: [message]
});
}
sendResponse({ status: "received" });
});

View File

@ -0,0 +1,37 @@
function sendEventToPage(id, data) {
document.dispatchEvent(new CustomEvent("olala", { detail: data }));
}
var ENGINE_VERSION = 1;
var ENGINE_MESSAGE_CHECK = "onlyoffice-engine-check";
var ENGINE_MESSAGE_DATA = "onlyoffice-engine-data";
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.action === "popupMessage") {
console.log("Сообщение из popup:", message.text);
if (window.pluginEngine && window.pluginEngine.onMessageFromPlugin)
window.pluginEngine.onMessageFromPlugin(message);
sendResponse({ status: "Сообщение получено!" });
sendEventToPage({ message: "Привет от content.js" });
}
});
// event from page with info about engine (is exist, version...)
document.addEventListener(ENGINE_MESSAGE_CHECK + "-page", (event) => {
document.dispatchEvent(new CustomEvent(ENGINE_MESSAGE_CHECK + "-content", { detail: { version : ENGINE_VERSION } }));
});
// event from page with action (proxy to background)
document.addEventListener(ENGINE_MESSAGE_DATA + "-page", (event) => {
chrome.runtime.sendMessage({
id : ENGINE_MESSAGE_DATA + "-engine",
data : event.detail
});
});
document.addEventListener(ENGINE_MESSAGE_DATA + "-engine", (event) => {
document.dispatchEvent(new CustomEvent(ENGINE_MESSAGE_DATA + "-content", event.detail));
});

View File

@ -0,0 +1,31 @@
(function(window, undefined){
function Engine()
{
}
Engine.prototype.generateKeys = async function(alg, password, salt)
{
};
Engine.prototype.changePassword = async function(privateKey, passwordOld, passwordNew, salt)
{
};
Engine.prototype.sign = async function(privateKey, password, salt, xml)
{
};
// ENCRYPT
Engine.prototype.decrypt = async function(privateKeyEnc, password, salt, data)
{
};
Engine.prototype.encrypt = async function(publicKey, data)
{
};
window.cryptoJS = new Engine();
})(window, undefined);

View File

@ -0,0 +1,223 @@
(function(window, undefined){
WebAssembly.instantiateStreaming = undefined;
function MemoryData(ptr) {
this.ptr = ptr;
}
MemoryData.prototype.isValid = function() {
return (this.ptr === 0) ? false : true;
};
MemoryData.prototype.free = function() {
if (0 != this.ptr)
Module["_Crypto_Free"](this.ptr);
};
MemoryData.prototype.getData = function() {
let lenArray = new Int32Array(Module["HEAP8"].buffer, this.ptr, 4);
let len = lenArray[0];
return new Uint8Array(Module["HEAP8"].buffer, this.ptr + 4, len);
};
function StringPointer(pointer, len) {
this.ptr = pointer;
this.length = len;
}
StringPointer.prototype.free = function() {
if (0 !== this.ptr)
Module["_free"](this.ptr);
};
String.prototype.toUtf8Pointer = function(isNoEndNull) {
var tmp = this.toUtf8(isNoEndNull, true);
var pointer = Module["_malloc"](tmp.length);
if (0 == pointer)
return null;
Module["HEAP8"].set(tmp, pointer);
return new StringPointer(pointer,tmp.length);
};
function typedArrayToMemory(data)
{
var pointer = Module["_malloc"](data.length);
Module["HEAP8"].set(data, langBuffer);
return pointer;
}
function Engine()
{
this.isInit = false;
this.waitResolvers = [];
}
Engine.prototype.onLoad = function()
{
this.isInit = true;
for (let i = 0, len = this.waitResolvers.length; i < len; i++)
this.waitResolvers[i]();
this.waitResolvers = [];
};
Engine.prototype.init = async function()
{
if (this.isInit)
return;
return new Promise(resolve => (function(){
window.CryptoJS.waitResolvers.push(resolve);
})());
};
// SIGN
Engine.prototype.generateKeys = async function(alg, password, salt)
{
await this.init();
if (!salt)
salt = window.UtilsJS.toBase64(window.UtilsJS.random(32));
let algPtr = "ed25519".toUtf8Pointer();
let passwordPtr = password.toUtf8Pointer();
let saltPtr = salt.toUtf8Pointer();
let keys = Module["_Crypto_CreateKeys"](algPtr.ptr, passwordPtr.ptr, saltPtr.ptr);
algPtr.free();
passwordPtr.free();
saltPtr.free();
if (keys === 0)
return null;
let heap = Module["HEAP8"];
let currentStart = keys;
let currentEnd = currentStart;
while (heap[currentEnd] != 0)
currentEnd++;
let publicKey = "".fromUtf8(heap, currentStart, currentEnd - currentStart);
currentStart = currentEnd + 1;
currentEnd = currentStart;
while (heap[currentEnd] != 0)
currentEnd++;
let privateKey = "".fromUtf8(heap, currentStart, currentEnd - currentStart);
Module["_Crypto_Free"](keys);
return {
"salt": salt,
"privateKey": privateKey,
"publicKey": publicKey
};
};
Engine.prototype.changePassword = async function(privateKey, passwordOld, passwordNew, salt)
{
await this.init();
let privateKeyPtr = privateKey.toUtf8Pointer();
let passwordOldPtr = passwordOld.toUtf8Pointer();
let passwordNewPtr = passwordNew.toUtf8Pointer();
let saltPtr = salt.toUtf8Pointer();
let privateKeyEnc = Module["_Crypto_ChangePassword"](privateKeyPtr.ptr, passwordOldPtr.ptr, passwordNewPtr.ptr, saltPtr.ptr);
privateKeyPtr.free();
passwordOldPtr.free();
passwordNewPtr.free();
saltPtr.free();
if (privateKeyEnc === 0)
return null;
let heap = Module["HEAP8"];
let currentStart = privateKeyEnc;
let currentEnd = currentStart;
while (heap[currentEnd] != 0)
currentEnd++;
let privateKeyString = "".fromUtf8(heap, currentStart, currentEnd - currentStart);
Module["_Crypto_Free"](privateKeyEnc);
return privateKeyString;
};
Engine.prototype.sign = async function(privateKey, password, salt, xml)
{
await this.init();
let privateKeyPtr = privateKey.toUtf8Pointer();
let passwordPtr = password.toUtf8Pointer();
let saltPtr = salt.toUtf8Pointer();
let xmlPtr = xml.toUtf8Pointer();
let signData = Module["_Crypto_Sign"](privateKeyPtr.ptr, passwordPtr.ptr, saltPtr.ptr, xmlPtr.ptr, xmlPtr.length);
privateKeyPtr.free();
passwordPtr.free();
saltPtr.free();
xmlPtr.free();
if (signData === 0)
return null;
let heap = Module["HEAP8"];
let currentStart = signData;
let currentEnd = currentStart;
while (heap[currentEnd] != 0)
currentEnd++;
let signString = "".fromUtf8(heap, currentStart, currentEnd - currentStart);
Module["_Crypto_Free"](signData);
return signString;
};
// ENCRYPT
Engine.prototype.decrypt = async function(privateKeyEnc, password, salt, data)
{
await this.init();
let privateKeyEncPtr = privateKeyEnc.toUtf8Pointer();
let passwordPtr = password.toUtf8Pointer();
let saltPtr = salt.toUtf8Pointer();
let dataPtr = typedArrayToMemory(data);
let decryptData = Module["_Crypto_Decrypt"](privateKeyEncPtr, passwordPtr, saltPtr.ptr, dataPtr, data.length);
let memoryData = new CMemoryData(decryptData);
privateKeyEncPtr.free();
passwordPtr.free();
saltPtr.free();
Module["_free"](dataPtr);
return memoryData;
};
Engine.prototype.encrypt = async function(publicKey, data)
{
await this.init();
let publicKeyEncPtr = publicKey.toUtf8Pointer();
let dataPtr = typedArrayToMemory(data);
let encryptData = Module["_Crypto_Encrypt"](publicKeyEncPtr, dataPtr, data.length);
let memoryData = new CMemoryData(decryptData);
publicKeyEncPtr.free();
Module["_free"](dataPtr);
return memoryData;
};
window.cryptoJS = new Engine();
//module
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 999 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

View File

@ -0,0 +1,43 @@
{
"manifest_version": 3,
"name": "ONLYOFFICE Keychain",
"version": "1.0",
"permissions": ["tabs", "scripting"],
"icons": {
"16": "icons/icon16.png",
"32": "icons/icon32.png",
"48": "icons/icon48.png",
"64": "icons/icon64.png",
"128": "icons/icon128.png"
},
"background": {
"service_worker": "background.js"
},
"host_permissions": ["<all_urls>"],
"action": {
"default_icon": {
"16": "icons/icon16.png",
"32": "icons/icon32.png",
"48": "icons/icon48.png",
"64": "icons/icon64.png",
"128": "icons/icon128.png"
},
"default_popup": "popup.html"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"]
}
],
"web_accessible_resources": [
{
"resources": ["engine.wasm"],
"matches": ["<all_urls>"]
}
],
"content_security_policy": {
"extension_pages" : "script-src 'self' 'wasm-unsafe-eval'; object-src 'self'"
}
}

View File

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Popup</title>
</head>
<body>
<h2>Сообщение получено!</h2>
<div id="message"></div>
<button id="testButton">buttton</button>
<script src="popup.js"></script>
</body>
</html>

View File

@ -0,0 +1,17 @@
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
document.getElementById("message").innerText = JSON.stringify(message);
});
document.addEventListener("DOMContentLoaded", (event) => {
document.getElementById("testButton").onclick = function(e) {
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
if (tabs.length === 0) return;
chrome.tabs.sendMessage(tabs[0].id, { action: "popupMessage", text: "Привет от Popup!" }, (response) => {
console.log("Ответ от контентного скрипта:", response);
});
});
};
});

View File

@ -0,0 +1,22 @@
import sys
sys.path.append("../../../../../../../build_tools/scripts")
import base
import argparse
parser = argparse.ArgumentParser(description='Generate background script for debug')
parser.add_argument("--wasm", action="store_true")
args = parser.parse_args()
content = base.readFile("./utils.js") + "\n\n"
if args.wasm:
content = content + "\n\n" + base.readFile("./../deploy/engine.js")
base.copy_file("./../deploy/engine.wasm", "./engine.wasm")
else:
content = content + "\n\n" + base.readFile("./engine.js")
content = content + "\n\n" + base.readFile("./background_base.js")
base.delete_file("./background.js")
base.writeFile("./background.js", content)

View File

@ -0,0 +1,334 @@
(function(window, undefined) {
if (undefined !== String.prototype.fromUtf8 && undefined !== String.prototype.toUtf8)
return;
var STRING_UTF8_BUFFER_LENGTH = 1024;
var STRING_UTF8_BUFFER = new ArrayBuffer(STRING_UTF8_BUFFER_LENGTH);
/**
* Read string from utf8
* @param {Uint8Array} buffer
* @param {number} [start=0]
* @param {number} [len]
* @returns {string}
*/
String.prototype.fromUtf8 = function(buffer, start, len) {
if (undefined === start)
start = 0;
if (undefined === len)
len = buffer.length - start;
var result = "";
var index = start;
var end = start + len;
while (index < end) {
var u0 = buffer[index++];
if (!(u0 & 128)) {
result += String.fromCharCode(u0);
continue;
}
var u1 = buffer[index++] & 63;
if ((u0 & 224) == 192) {
result += String.fromCharCode((u0 & 31) << 6 | u1);
continue;
}
var u2 = buffer[index++] & 63;
if ((u0 & 240) == 224)
u0 = (u0 & 15) << 12 | u1 << 6 | u2;
else
u0 = (u0 & 7) << 18 | u1 << 12 | u2 << 6 | buffer[index++] & 63;
if (u0 < 65536)
result += String.fromCharCode(u0);
else {
var ch = u0 - 65536;
result += String.fromCharCode(55296 | ch >> 10, 56320 | ch & 1023);
}
}
return result;
};
/**
* Convert string to utf8 array
* @returns {Uint8Array}
*/
String.prototype.toUtf8 = function(isNoEndNull, isUseBuffer) {
var inputLen = this.length;
var testLen = 6 * inputLen + 1;
var tmpStrings = (isUseBuffer && testLen < STRING_UTF8_BUFFER_LENGTH) ? STRING_UTF8_BUFFER : new ArrayBuffer(testLen);
var code = 0;
var index = 0;
var outputIndex = 0;
var outputDataTmp = new Uint8Array(tmpStrings);
var outputData = outputDataTmp;
while (index < inputLen) {
code = this.charCodeAt(index++);
if (code >= 0xD800 && code <= 0xDFFF && index < inputLen)
code = 0x10000 + (((code & 0x3FF) << 10) | (0x03FF & this.charCodeAt(index++)));
if (code < 0x80)
outputData[outputIndex++] = code;
else if (code < 0x0800) {
outputData[outputIndex++] = 0xC0 | (code >> 6);
outputData[outputIndex++] = 0x80 | (code & 0x3F);
} else if (code < 0x10000) {
outputData[outputIndex++] = 0xE0 | (code >> 12);
outputData[outputIndex++] = 0x80 | ((code >> 6) & 0x3F);
outputData[outputIndex++] = 0x80 | (code & 0x3F);
} else if (code < 0x1FFFFF) {
outputData[outputIndex++] = 0xF0 | (code >> 18);
outputData[outputIndex++] = 0x80 | ((code >> 12) & 0x3F);
outputData[outputIndex++] = 0x80 | ((code >> 6) & 0x3F);
outputData[outputIndex++] = 0x80 | (code & 0x3F);
} else if (code < 0x3FFFFFF) {
outputData[outputIndex++] = 0xF8 | (code >> 24);
outputData[outputIndex++] = 0x80 | ((code >> 18) & 0x3F);
outputData[outputIndex++] = 0x80 | ((code >> 12) & 0x3F);
outputData[outputIndex++] = 0x80 | ((code >> 6) & 0x3F);
outputData[outputIndex++] = 0x80 | (code & 0x3F);
} else if (code < 0x7FFFFFFF) {
outputData[outputIndex++] = 0xFC | (code >> 30);
outputData[outputIndex++] = 0x80 | ((code >> 24) & 0x3F);
outputData[outputIndex++] = 0x80 | ((code >> 18) & 0x3F);
outputData[outputIndex++] = 0x80 | ((code >> 12) & 0x3F);
outputData[outputIndex++] = 0x80 | ((code >> 6) & 0x3F);
outputData[outputIndex++] = 0x80 | (code & 0x3F);
}
}
if (isNoEndNull !== true)
outputData[outputIndex++] = 0;
return new Uint8Array(tmpStrings,0,outputIndex);
};
window.UtilsJS = {};
var charA = "A".charCodeAt(0);
var charZ = "Z".charCodeAt(0);
var chara = "a".charCodeAt(0);
var charz = "z".charCodeAt(0);
var char0 = "0".charCodeAt(0);
var char9 = "9".charCodeAt(0);
var charp = "+".charCodeAt(0);
var chars = "/".charCodeAt(0);
var char_break = ";".charCodeAt(0);
function decodeBase64Char(ch)
{
if (ch >= charA && ch <= charZ)
return ch - charA + 0;
if (ch >= chara && ch <= charz)
return ch - chara + 26;
if (ch >= char0 && ch <= char9)
return ch - char0 + 52;
if (ch == charp)
return 62;
if (ch == chars)
return 63;
return -1;
}
var stringBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var arrayBase64 = [];
for (var index64 = 0; index64 < stringBase64.length; index64++)
{
arrayBase64.push(stringBase64.charAt(index64));
}
window.UtilsJS.Base64 = {};
window.UtilsJS.Base64.decodeData = function(input, input_offset, input_len, output, output_offset)
{
var isBase64 = typeof input === "string";
if (undefined === input_len) input_len = input.length;
var writeIndex = (undefined === output_offset) ? 0 : output_offset;
var index = (undefined === input_offset) ? 0 : input_offset;
while (index < input_len)
{
var dwCurr = 0;
var i;
var nBits = 0;
for (i=0; i<4; i++)
{
if (index >= input_len)
break;
var nCh = decodeBase64Char(isBase64 ? input.charCodeAt(index) : input[index]);
index++;
if (nCh == -1)
{
i--;
continue;
}
dwCurr <<= 6;
dwCurr |= nCh;
nBits += 6;
}
dwCurr <<= 24-nBits;
for (i=0; i<(nBits>>3); i++)
{
output[writeIndex++] = ((dwCurr & 0x00ff0000) >>> 16);
dwCurr <<= 8;
}
}
return writeIndex;
};
window.UtilsJS.Base64.decode = function(input, isUsePrefix, dstlen, offset)
{
var srcLen = input.length;
var index = (undefined === offset) ? 0 : offset;
var dstLen = (undefined === dstlen) ? srcLen : dstlen;
var isBase64 = typeof input === "string";
if (isUsePrefix && isBase64)
{
dstLen = 0;
var maxLen = Math.max(11, srcLen); // > 4 Gb
while (index < maxLen)
{
var c = input.charCodeAt(index++);
if (c == char_break)
break;
dstLen *= 10;
dstLen += (c - char0);
}
if (index == maxLen)
{
index = 0;
dstLen = srcLen;
}
}
var dst = new Uint8Array(dstLen);
var writeIndex = window.AscCommon.Base64.decodeData(input, index, srcLen, dst, 0);
if (writeIndex == dstLen)
return dst;
return new Uint8Array(dst.buffer, 0, writeIndex);
};
window.UtilsJS.Base64.encode = function(input, offset, length, isUsePrefix)
{
var srcLen = (undefined === length) ? input.length : length;
var index = (undefined === offset) ? 0 : offset;
var len1 = (((srcLen / 3) >> 0) * 4);
var len2 = (len1 / 76) >> 0;
var len3 = 19;
var dstArray = [];
var sTemp = "";
var dwCurr = 0;
for (var i = 0; i <= len2; i++)
{
if (i == len2)
len3 = ((len1 % 76) / 4) >> 0;
for (var j = 0; j < len3; j++)
{
dwCurr = 0;
for (var n = 0; n < 3; n++)
{
dwCurr |= input[index++];
dwCurr <<= 8;
}
sTemp = "";
for (var k = 0; k < 4; k++)
{
var b = (dwCurr >>> 26) & 0xFF;
sTemp += arrayBase64[b];
dwCurr <<= 6;
dwCurr &= 0xFFFFFFFF;
}
dstArray.push(sTemp);
}
}
len2 = (srcLen % 3 != 0) ? (srcLen % 3 + 1) : 0;
if (len2)
{
dwCurr = 0;
for (var n = 0; n < 3; n++)
{
if (n < (srcLen % 3))
dwCurr |= input[index++];
dwCurr <<= 8;
}
sTemp = "";
for (var k = 0; k < len2; k++)
{
var b = (dwCurr >>> 26) & 0xFF;
sTemp += arrayBase64[b];
dwCurr <<= 6;
}
len3 = (len2 != 0) ? 4 - len2 : 0;
for (var j = 0; j < len3; j++)
{
sTemp += '=';
}
dstArray.push(sTemp);
}
return isUsePrefix ? (("" + srcLen + ";") + dstArray.join("")) : dstArray.join("");
};
window.UtilsJS.Hex = {};
window.UtilsJS.Hex.decode = function(input)
{
var hexToByte = function(c) {
if (c >= 48 && c <= 57) return c - 48; // 0..9
if (c >= 97 && c <= 102) return c - 87;
if (c >= 65 && c <= 70) return c - 55;
return 0;
};
var len = input.length;
if (len & 0x01) len -= 1;
var result = new Uint8Array(len >> 1);
var resIndex = 0;
for (var i = 0; i < len; i += 2)
{
result[resIndex++] = hexToByte(input.charCodeAt(i)) << 4 | hexToByte(input.charCodeAt(i + 1));
}
return result;
};
window.UtilsJS.Hex.encode = function(input, isUpperCase)
{
var byteToHex = new Array(256);
for (var i = 0; i < 16; i++)
byteToHex[i] = "0" + (isUpperCase ? i.toString(16).toUpperCase() : i.toString(16));
for (var i = 16; i < 256; i++)
byteToHex[i] = isUpperCase ? i.toString(16).toUpperCase() : i.toString(16);
var result = "";
for (var i = 0, len = input.length; i < len; i++)
result += byteToHex[input[i]];
return result;
};
window.UtilsJS.random = function(length) {
let byteArray = new Uint8Array(length);
let engine = window.crypto || window.msCrypto;
if (engine)
engine.getRandomValues(byteArray);
else {
for (let i = 0; i < length; i++)
byteArray[i] = (Math.random() * 256) >> 0;
}
return byteArray;
};
})(self);

View File

@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

@ -0,0 +1,6 @@
# Onlyoffice keychain extension
To run the dev build:
1. Go to the extension2 folder
2. Run ```npm run dev```
3. Upload the dist folder as an unpacked extension to the browser

View File

@ -0,0 +1,26 @@
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'
import { globalIgnores } from 'eslint/config'
export default tseslint.config([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
js.configs.recommended,
tseslint.configs.recommended,
reactHooks.configs['recommended-latest'],
reactRefresh.configs.vite,
],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
rules: {
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
}
},
])

View File

@ -0,0 +1,34 @@
import { defineManifest } from '@crxjs/vite-plugin';
import pkg from "./package.json";
export default defineManifest({
manifest_version: 3,
name: pkg.name,
version: pkg.version,
icons: {
16: "public/icons/icon16.png",
32: "public/icons/icon32.png",
48: "public/icons/icon48.png",
64: "public/icons/icon64.png",
128: "public/icons/icon128.png",
},
action: {
default_icon: {
16: "public/icons/icon16.png",
32: "public/icons/icon32.png",
48: "public/icons/icon48.png",
64: "public/icons/icon64.png",
128: "public/icons/icon128.png",
},
default_popup: 'src/popup/index.html',
},
content_scripts: [{
js: ['src/content/content.ts'],
matches: ['<all_urls>'],
run_at: "document_end"
}],
background: {
service_worker: "src/background/background.ts"
},
permissions: ["storage"],
});

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,33 @@
{
"name": "ONLYOFFICE Keychain",
"private": true,
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint .",
"preview": "vite preview"
},
"dependencies": {
"react": "^19.1.1",
"react-dom": "^19.1.1",
"webextension-polyfill": "^0.12.0"
},
"devDependencies": {
"@crxjs/vite-plugin": "^2.2.0",
"@eslint/js": "^9.33.0",
"@types/react": "^19.1.10",
"@types/react-dom": "^19.1.7",
"@types/webextension-polyfill": "^0.12.3",
"@vitejs/plugin-react": "^5.0.0",
"chrome-types": "^0.1.375",
"eslint": "^9.33.0",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.20",
"globals": "^16.3.0",
"typescript": "~5.8.3",
"typescript-eslint": "^8.39.1",
"vite": "^7.1.5"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 999 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

View File

@ -0,0 +1,5 @@
import {initCheckOpenedPopup} from "./utils.ts";
import initTaskManager from "./task-manager/task-manager.ts";
initTaskManager();
initCheckOpenedPopup();

View File

@ -0,0 +1,31 @@
import browser from "webextension-polyfill";
import {messageTypes} from "../../common/message-const.ts";
import {generatePopupKeys, selectSignKeys, signData, verifyData} from "./tasks.ts";
import {isBackgroundMessageType} from "../../common/message-types.ts";
const initTaskManager = () => {
browser.runtime.onMessage.addListener((message: unknown) => {
if (!isBackgroundMessageType(message)) {
return false;
}
const data = message.data;
switch (data.type) {
case messageTypes.GENERATE_KEYS: {
return generatePopupKeys();
}
case messageTypes.SELECT_SIGN_KEYS: {
return selectSignKeys();
}
case messageTypes.SIGN_DATA: {
return signData(data.base64Data, data.guid);
}
case messageTypes.VERIFY_DATA: {
return verifyData(data.base64Data, data.base64Signature, data.guid);
}
default:
return false;
}
});
}
export default initTaskManager;

View File

@ -0,0 +1,43 @@
import {openPopup} from "../utils.ts";
import {messageTypes} from "../../common/message-const.ts";
import {sendToPopup} from "../../content/messenger.ts";
// @ts-ignore
import {StorageManager} from "../../common/storage.ts";
import {ab2base64, base642ui} from "../../common/utils.ts";
import getCrypto from "../../common/crypto.ts";
export const generatePopupKeys = async () => {
await openPopup();
await sendToPopup({type: messageTypes.WAIT_ENTER_PASSWORD});
return true;
}
export const selectSignKeys = async () => {
await openPopup();
await sendToPopup({type: messageTypes.WAIT_ENTER_PASSWORD});
return await sendToPopup({type: messageTypes.SELECT_SIGN_KEYS});
};
export const signData = async (base64Data: string , guid: string) => {
const keyStorage = new StorageManager();
await keyStorage.loadKeysFromStorage();
const keyPair = keyStorage.getKeyByGuid(guid);
if (!keyPair) {
throw new Error("Key pair is not found");
}
const data = base642ui(base64Data);
const signData = await keyPair.sign(data);
return ab2base64(signData);
}
export const verifyData = async (base64Data: string, base64Signature: string, guid: string) => {
const keyStorage = new StorageManager();
await keyStorage.loadKeysFromStorage();
const keyPair = keyStorage.getKeyByGuid(guid);
if (!keyPair) {
throw new Error("Key pair is not found");
}
const data = base642ui(base64Data);
const signature = base642ui(base64Signature);
return await keyPair.verify(signature, data);
}

View File

@ -0,0 +1,52 @@
import browser from "webextension-polyfill";
import getCrypto from "../common/crypto.ts";
export const initCheckOpenedPopup = () => {
browser.runtime.onConnect.addListener((port) => {
if (port.name === "popup") {
browser.storage.session.set({isOpenPopup: true});
port.onDisconnect.addListener(() => {
browser.storage.session.set({isOpenPopup: false});
});
}
});
};
const isOpenedPopup = async () => {
const isOpenPopupItem = await browser.storage.session.get("isOpenPopup");
return !!(isOpenPopupItem && isOpenPopupItem.isOpenPopup);
};
const waitClosingPopup = async () => {
const isOpenPopup = await isOpenedPopup();
if (!isOpenPopup) {
return true;
}
return new Promise(resolve => {
browser.storage.session.onChanged.addListener(function handler(change) {
if (change.isOpenPopup && !change.isOpenPopup.newValue) {
browser.storage.session.onChanged.removeListener(handler);
resolve(true);
}
});
});
};
export const openPopup = async () => {
await waitClosingPopup();
await browser.action.openPopup();
return new Promise(resolve => {
browser.storage.session.onChanged.addListener(function handler(change) {
if (change.isOpenPopup && change.isOpenPopup.newValue) {
browser.storage.session.onChanged.removeListener(handler);
resolve(true);
}
});
});
};
type TGuid = `{${string}-${string}-${string}-${string}-${string}}`
export const getGUID = (): TGuid => {
const crypto = getCrypto();
return `{${crypto.randomUUID()}}`;
}

View File

@ -0,0 +1,138 @@
import {Key, KeyPair, KeyUsages, PrivateKey, PublicKey, SymmetricKey} from "./keys/keys.ts";
import {
type DigestType,
digestTypes,
type ExportKeyFormat,
exportKeyFormats,
type KeyGenParams,
type KeyParams
} from "./keys/key-types.ts";
import {AesGcmGenParams, type AesGcmParams} from "./keys/params.ts";
const pbkdf2Parameters = {
iterations: 150000,
hash: digestTypes.SHA256,
saltLength: 16
};
// type DecryptKey = PrivateKey | SymmetricKey;
// type EncryptKey = PublicKey | SymmetricKey;
abstract class CCryptoBase {
abstract sign(key: PrivateKey, data: ArrayBuffer): Promise<ArrayBuffer>;
abstract digest(algorithm: DigestType, data: ArrayBuffer): Promise<ArrayBuffer>;
abstract verify(key: PublicKey, signature: ArrayBuffer, data: ArrayBuffer): Promise<boolean>;
// abstract decrypt(key: DecryptKey, data: ArrayBuffer): Promise<ArrayBuffer>;
// abstract encrypt(key: EncryptKey, data: ArrayBuffer): Promise<ArrayBuffer>;
abstract generateKey(params: KeyGenParams, keyUsage: KeyUsages): Promise<SymmetricKey | KeyPair>;
abstract wrapKey(format: ExportKeyFormat, key: Key, masterPassword: ArrayBuffer, salt: ArrayBuffer, aesParams: AesGcmParams, keyUsage: KeyUsages): Promise<ArrayBuffer>
abstract unwrapKey(format: ExportKeyFormat, key: ArrayBuffer, masterPassword: ArrayBuffer, salt: ArrayBuffer, aesParams: AesGcmParams, keyParams: KeyParams, keyUsage: KeyUsages): Promise<ArrayBuffer>
abstract getRandomValues(length: number): ArrayBuffer;
abstract randomUUID(): string;
}
class CWebCrypto extends CCryptoBase {
crypto = globalThis.crypto;
subtle = this.crypto.subtle;
constructor() {
super();
}
getRandomValues(length: number) {
const ui = new Uint8Array(length);
return this.crypto.getRandomValues(ui);
}
async getAesCryptoKey(masterPassword: ArrayBuffer, salt: ArrayBuffer) {
const pwKey = await this.subtle.importKey(
'raw',
masterPassword,
{ name: 'PBKDF2' },
false,
['deriveKey']
);
return this.subtle.deriveKey(
{
name: 'PBKDF2',
salt: salt,
iterations: pbkdf2Parameters.iterations,
hash: pbkdf2Parameters.hash
},
pwKey,
new AesGcmGenParams(),
false,
['wrapKey', 'unwrapKey']
);
};
async wrapKey(format: ExportKeyFormat, key: Key, masterPassword: ArrayBuffer, salt: ArrayBuffer, aesParams: AesGcmParams, keyUsage: KeyUsages) {
const cryptoAesKey = await this.getAesCryptoKey(masterPassword, salt);
const importKey = await this.getCryptoKeyFromWrapper(key, keyUsage);
return this.subtle.wrapKey(format, importKey, cryptoAesKey, aesParams);
}
async unwrapKey(format: ExportKeyFormat, key: ArrayBuffer, masterPassword: ArrayBuffer, salt: ArrayBuffer, aesParams: AesGcmParams, keyParams: KeyParams, keyUsages: KeyUsages) {
const cryptoAesKey = await this.getAesCryptoKey(masterPassword, salt);
const cryptoKey = await this.subtle.unwrapKey(format, key, cryptoAesKey, aesParams, keyParams, true, /*this.getKeyUsages(keyUsages)*/["sign"]);
return this.subtle.exportKey(format, cryptoKey);
}
async getCryptoKeyFromWrapper(key: Key, keyUsage: KeyUsages) {
return this.subtle.importKey(key.exportFormat, key.key, key.params, true, this.getKeyUsages(keyUsage, key));
}
getKeyUsages({isEncrypt, isSign}: KeyUsages, key?: Key) {
const keyUsages: KeyUsage[] = [];
if (isEncrypt) {
if (key instanceof PrivateKey) {
keyUsages.push("decrypt");
} else if (key instanceof PublicKey) {
keyUsages.push("encrypt");
} else {
keyUsages.push("encrypt", "decrypt");
}
}
if (isSign) {
if (key instanceof PrivateKey) {
keyUsages.push("sign");
} else if (key instanceof PublicKey) {
keyUsages.push("verify");
} else {
keyUsages.push("sign", "verify");
}
}
return keyUsages;
}
async sign(key: PrivateKey, data: ArrayBuffer): Promise<ArrayBuffer> {
const cryptoKey = await this.getCryptoKeyFromWrapper(key, new KeyUsages(false, true));
return this.subtle.sign(key.params, cryptoKey, data);
}
async digest(algorithm: DigestType, data: ArrayBuffer): Promise<ArrayBuffer> {
return this.subtle.digest(algorithm, data);
}
async verify(key: PublicKey, signature: ArrayBuffer, data: ArrayBuffer): Promise<boolean> {
const cryptoKey = await this.getCryptoKeyFromWrapper(key, new KeyUsages(false, true));
return this.subtle.verify(key.params, cryptoKey, signature, data);
}
// async decrypt(key: DecryptKey, data: ArrayBuffer): Promise<ArrayBuffer> {
// const cryptoKey = await this.getCryptoKeyFromWrapper(key);
// return this.subtle.decrypt(cryptoKey);
// }
// async encrypt(key: EncryptKey, data: ArrayBuffer): Promise<ArrayBuffer> {
// throw new Error("Method not implemented.");
// }
async generateKey(params: KeyGenParams, keyUsage: KeyUsages) {
const cryptoKey = await this.subtle.generateKey(params, true, this.getKeyUsages(keyUsage));
const importParams = params.getImportParams();
if (("privateKey" in cryptoKey) && ("publicKey" in cryptoKey)) {
const publicKeyBuffer = await this.subtle.exportKey(exportKeyFormats.spki, cryptoKey.publicKey);
const publicKey = new PublicKey(publicKeyBuffer, importParams);
const privateKeyBuffer = await this.subtle.exportKey(exportKeyFormats.pkcs8, cryptoKey.privateKey);
const privateKey = new PrivateKey(privateKeyBuffer, importParams, this.getRandomValues(pbkdf2Parameters.saltLength));
return new KeyPair(publicKey, privateKey, keyUsage);
}
const keyBuffer = await this.subtle.exportKey(exportKeyFormats.raw, cryptoKey);
return new SymmetricKey(keyBuffer, importParams, keyUsage);
};
randomUUID() {
return this.crypto.randomUUID();
}
}
const getCrypto = () => {
return new CWebCrypto();
}
export default getCrypto;

View File

@ -0,0 +1,73 @@
import {KeyStorage} from "key-storage";
import {downloadBinary, selectBinary} from "./utils.ts";
export function StorageManager() {
this.keyStorage = new KeyStorage();
}
StorageManager.prototype.getBinaryKeys = function () {
return Promise.resolve(null);
};
StorageManager.prototype.loadKeysFromStorage = function() {
const oThis = this;
return Promise.all([this.getMasterPassword(), this.getBinaryKeys()]).then(function ([masterPassword, binaryData]) {
return oThis.keyStorage.import(binaryData, masterPassword);
});
}
StorageManager.prototype.changeMasterPassword = function(newMasterPassword) {
const oThis = this;
return this.getMasterPassword().then(function (oldMasterPassword) {
return oThis.keyStorage.changeMasterPassword(oldMasterPassword, newMasterPassword);
});
};
StorageManager.prototype.getMasterPassword = function() {
return Promise.resolve(null);
};
StorageManager.prototype.writeKeys = function() {
const oThis = this;
return this.keyStorage.export().then(function (exportedKeys) {
return oThis.setStorageKeys(exportedKeys);
});
}
StorageManager.prototype.setStorageKeys = function (exportedKeys) {
return Promise.resolve();
};
StorageManager.prototype.addNewKeys = function (keys) {
this.keyStorage.addKeys(keys);
return this.writeKeys();
};
StorageManager.prototype.deprecateKey = function (key) {
key.setIsValid(false);
return this.writeKeys();
};
StorageManager.prototype.exportKeys = function () {
return this.keyStorage.export().then(downloadBinary);
};
StorageManager.prototype.importKeys = function (callback) {
const oThis = this;
return this.getMasterPassword().then(function (masterPassword) {
selectBinary(function (file) {
try {
file.arrayBuffer().then(function (binaryData) {
return oThis.keyStorage.import(binaryData, masterPassword);
}).then(function (keyObjects) {
return oThis.addNewKeys(keyObjects);
}).then(function () {
callback();
});
} catch (e) {
}
});
})
};
StorageManager.prototype.generateKeys = function (params) {
return this.keyStorage.generateKey(params);
};
StorageManager.prototype.getValidKeys = function () {
return this.keyStorage.getValidKeys();
};
StorageManager.prototype.getKeyByGuid = function (guid) {
return this.keyStorage.getKeyByGuid(guid);
};

View File

@ -0,0 +1,108 @@
import {
AesGcmParams,
AesImportParams,
AesKeyGenParams, Ed25519ImportParams,
Ed25519KeyGenParams,
type RsaImportParams,
RSAKeyGenParams
} from "./params.ts";
import {Key, KeyPair, PrivateKey, PublicKey} from "./keys.ts";
export const exportKeyFormats = {
pkcs8: "pkcs8",
spki: "spki",
raw: "raw"
} as const;
export const algorithmTypes = {
AES_GCM: "AES-GCM",
AES_CTR: "AES-CTR",
AES_CBC: "AES-CBC",
AES_KW: "AES-KW",
ED25519: "Ed25519",
RSASSA_PKCS1_v1_5: "RSASSA-PKCS1-v1_5",
RSA_PSS: "RSA-PSS",
RSA_OAEP: "RSA-OAEP"
} as const;
export const rsaTypes = {
RSASSA_PKCS1_v1_5: algorithmTypes.RSASSA_PKCS1_v1_5,
RSA_PSS: algorithmTypes.RSA_PSS,
RSA_OAEP: algorithmTypes.RSA_OAEP,
} as const;
export const aesTypes = {
AES_GCM: algorithmTypes.AES_GCM,
AES_CTR: algorithmTypes.AES_CTR,
AES_CBC: algorithmTypes.AES_CBC,
AES_KW: algorithmTypes.AES_KW,
} as const;
export const digestTypes = {
SHA1: "SHA-1",
SHA256: "SHA-256",
SHA384: "SHA-384",
SHA512: "SHA-512",
} as const;
export const keyTypes = {
symmetric: "symmetric",
pair: "pair"
} as const;
export const pairKeyTypes = {
private: "private",
public: "public",
} as const;
export const signAlgorithms = {
ED25519: algorithmTypes.ED25519
}
export const cryptAlgorithms = {
...aesTypes,
RSA_OAEP: algorithmTypes.RSA_OAEP
}
export const isRSAJson = (obj: JSONKeyParams): obj is RsaJSONType => {
const name = obj.name;
return Object.values(rsaTypes).includes(name as RsaType);
}
export const isEd25519Json = (obj: JSONKeyParams): obj is Ed25519JSONParams => {
const name = obj.name;
return name === algorithmTypes.ED25519;
};
export const isAesJson = (obj: JSONKeyParams): obj is AesJSONType => {
const name = obj.name;
return Object.values(aesTypes).includes(name as AesType);
}
export type RsaJSONType = ReturnType<RsaImportParams["toJSON"]>;
export type AesJSONType = ReturnType<AesImportParams["toJSON"]>;
export type Ed25519JSONParams = ReturnType<Ed25519ImportParams["toJSON"]>;
export type JSONAesGcmParams = ReturnType<AesGcmParams["toJSON"]>;
export type AesKeyGenLength = 128 | 192 | 256;
export type KeyParams = RsaImportParams | AesImportParams | Ed25519ImportParams;
export type JSONKeyParams = RsaJSONType | AesJSONType | Ed25519JSONParams;
export type KeyGenParams = RSAKeyGenParams | Ed25519KeyGenParams | AesKeyGenParams;
export type DigestType = typeof digestTypes[keyof typeof digestTypes];
export type AesType = typeof aesTypes[keyof typeof aesTypes];
export type RsaType = typeof rsaTypes[keyof typeof rsaTypes];
export type AlgorithmType = typeof algorithmTypes[keyof typeof algorithmTypes];
export type ExportKeyFormat = typeof exportKeyFormats[keyof typeof exportKeyFormats];
export type SignAlgorithm = typeof signAlgorithms[keyof typeof signAlgorithms];
export type CryptAlgorithm = typeof cryptAlgorithms[keyof typeof cryptAlgorithms];
export type JSONKey = Awaited<ReturnType<Key["toJSON"]>>;
export type JSONPublicKey = Awaited<ReturnType<PublicKey["toJSON"]>>;
export type JSONPrivateKey = Awaited<ReturnType<PrivateKey["toJSON"]>>;
export type JSONKeyPair = Awaited<ReturnType<KeyPair["toJSON"]>>;
export type PairKey = PrivateKey | PublicKey;
type JSONEncryptExportKeyFormat = {
encrypt: true;
salt: string;
data: string;
};
type JSONDecryptExportKeyFormat = {
encrypt: false;
data: JSONKeyPair[];
};
export type JSONExportKeyFormat = JSONEncryptExportKeyFormat | JSONDecryptExportKeyFormat;

View File

@ -0,0 +1,156 @@
import {getGUID} from "../../background/utils.ts";
import {ab2base64, base642ui, str2ui} from "../utils.ts";
import {
type ExportKeyFormat,
exportKeyFormats, type JSONKey, type JSONKeyPair, type JSONPrivateKey, type JSONPublicKey,
type KeyParams,
keyTypes,
pairKeyTypes
} from "./key-types.ts";
import getCrypto from "../crypto.ts";
import {AesGcmParams, getKeyParamsFromJson} from "./params.ts";
export class Key {
params: KeyParams;
key;
exportFormat;
constructor(key: ArrayBuffer, params: KeyParams, exportFormat: ExportKeyFormat) {
this.key = key;
this.params = params;
this.exportFormat = exportFormat;
}
static async fromJSON(json: JSONKey, _masterPassword?: string, _keyUsage?: KeyUsages) {
const params = getKeyParamsFromJson(json.params);
const key = base642ui(json.key);
return new this(key, params, exportKeyFormats.raw);
}
async toJSON(_masterPassword?: string, _keyUsage?: KeyUsages) {
const key = ab2base64(this.key);
return {
params: this.params.toJSON(),
key: key
};
}
}
export class SymmetricKey extends Key {
type = keyTypes.symmetric;
keyUsages;
constructor(key: ArrayBuffer, params: KeyParams, keyUsage = new KeyUsages(true)) {
super(key, params, exportKeyFormats.raw);
this.keyUsages = keyUsage;
}
}
export class PublicKey extends Key {
type = pairKeyTypes.public;
constructor(key: ArrayBuffer, params: KeyParams) {
super(key, params, exportKeyFormats.spki);
}
static override async fromJSON(json: JSONPublicKey) {
const params = getKeyParamsFromJson(json.params);
const key = base642ui(json.key);
return new PublicKey(key, params);
}
override async toJSON() {
const params = this.params.toJSON();
const base64Key = ab2base64(this.key);
return {
format: exportKeyFormats.spki,
key: base64Key,
params
};
}
}
export class PrivateKey extends Key {
type = pairKeyTypes.private;
salt;
constructor(key: ArrayBuffer, params: KeyParams, salt: ArrayBuffer) {
super(key, params, exportKeyFormats.pkcs8);
this.salt = salt;
}
static override async fromJSON(json: JSONPrivateKey, masterPassword: string, keyUsage: KeyUsages) {
const salt = base642ui(json.salt);
const params = getKeyParamsFromJson(json.params);
const crypto = getCrypto();
const strWrapKey = json.key;
const wrapKey = base642ui(strWrapKey);
const wrapParams = new AesGcmParams();
wrapParams.fromJSON(json.wrapParams);
const key = await crypto.unwrapKey(exportKeyFormats.pkcs8, wrapKey, str2ui(masterPassword), salt, wrapParams, params, keyUsage);
return new PrivateKey(key, params, salt);
}
override async toJSON(masterPassword: string, keyUsage: KeyUsages) {
const crypto = getCrypto();
const iv = crypto.getRandomValues(12);
const aesParams = new AesGcmParams(iv);
const wrapKey = await crypto.wrapKey(this.exportFormat, this, str2ui(masterPassword), this.salt, aesParams, keyUsage);
const base64WrapKey = ab2base64(wrapKey);
const params = this.params.toJSON();
const wrapParams = aesParams.toJSON();
return {
format: this.exportFormat,
key: base64WrapKey,
salt: ab2base64(this.salt),
params,
wrapParams
};
}
}
export class KeyPair {
privateKey;
publicKey;
date;
type = keyTypes.pair;
keyUsage;
guid;
isValid;
static async fromJSON(json: JSONKeyPair, masterPassword: string) {
const keyUsage = KeyUsages.fromJSON(json.keyUsage);
const publicKey = await PublicKey.fromJSON(json.publicKey);
const privateKey = await PrivateKey.fromJSON(json.privateKey, masterPassword, keyUsage);
const date = new Date(json.date);
const guid = json.guid;
const isValid = json.isValid;
return new KeyPair(publicKey, privateKey, keyUsage, date, guid, isValid);
}
constructor(publicKey: PublicKey, privateKey: PrivateKey, keyUsage = new KeyUsages(true), date = new Date(), guid: string = getGUID(), isValid: boolean = true) {
this.privateKey = privateKey;
this.publicKey = publicKey;
this.date = date;
this.keyUsage = keyUsage;
this.guid = guid;
this.isValid = isValid;
}
async toJSON(masterPassword: string) {
return {
publicKey: await this.publicKey.toJSON(),
privateKey: await this.privateKey.toJSON(masterPassword, this.keyUsage),
date: this.date.toISOString(),
keyUsage: this.keyUsage.toJSON(),
guid: this.guid,
isValid: this.isValid
}
}
setIsValid(isValid: boolean) {
this.isValid = isValid;
};
}
export class KeyUsages {
isEncrypt;
isSign;
constructor(isEncrypt?: boolean, isSign?: boolean) {
this.isEncrypt = !!isEncrypt;
this.isSign = !!isSign;
}
static fromJSON(json: ReturnType<KeyUsages["toJSON"]>) {
return new KeyUsages(json.isEncrypt, json.isSign);
}
toJSON() {
return {
isEncrypt: this.isEncrypt,
isSign: this.isSign
}
}
}

View File

@ -0,0 +1,128 @@
import {
type AesKeyGenLength,
type AesType,
aesTypes,
type AlgorithmType,
algorithmTypes,
type DigestType,
digestTypes, isAesJson, isEd25519Json,
isRSAJson,
type JSONAesGcmParams,
type JSONKeyParams,
type RsaJSONType,
type RsaType
} from "./key-types.ts";
import {ab2base64, base642ui} from "../utils.ts";
export const getKeyParamsFromJson = (keyParamsJson: JSONKeyParams) => {
if (isRSAJson(keyParamsJson)) {
return new RsaImportParams(keyParamsJson.name, keyParamsJson.hash);
}
if (isEd25519Json(keyParamsJson)) {
return new Ed25519ImportParams();
}
if (isAesJson(keyParamsJson)) {
return new AesImportParams(keyParamsJson.name);
}
throw new Error("Unknown param type");
};
export class AlgorithmParams<TName extends AlgorithmType = AlgorithmType> {
name: TName;
constructor(name: TName) {
this.name = name;
}
toJSON() {
return {
name: this.name
};
};
fromJSON(json: {name: TName}) {
this.name = json.name;
}
getImportParams() {
return new AlgorithmParams(this.name);
}
}
export class RsaImportParams extends AlgorithmParams<RsaType> {
hash;
constructor(name: RsaType, hash: DigestType = digestTypes.SHA256) {
super(name);
this.hash = hash;
}
override toJSON() {
return {
name: this.name,
hash: this.hash,
}
}
override fromJSON(json: RsaJSONType) {
this.name = json.name;
this.hash = json.hash;
}
}
export class RSAKeyGenParams extends RsaImportParams {
modulusLength;
publicExponent;
constructor(name: RsaType, hash: DigestType = digestTypes.SHA256, modulusLength = 2048, publicExponent = new Uint8Array([0x01, 0x00, 0x01])) {
super(name, hash);
this.modulusLength = modulusLength;
this.publicExponent = publicExponent;
}
override getImportParams() {
return new RsaImportParams(this.name, this.hash);
}
}
export class Ed25519ImportParams extends AlgorithmParams<typeof algorithmTypes.ED25519> {
constructor() {
super(algorithmTypes.ED25519);
}
}
export class AesImportParams extends AlgorithmParams<AesType> {
constructor(name: AesType) {
super(name);
}
}
export class AesGcmParams {
name = algorithmTypes.AES_GCM;
iv: ArrayBuffer;
constructor(iv: ArrayBuffer = new Uint8Array(12)) {
this.iv = iv;
}
toJSON() {
return {
name: this.name,
iv: ab2base64(this.iv)
}
};
fromJSON(json: JSONAesGcmParams) {
this.iv = base642ui(json.iv);
};
}
export class AesKeyGenParams extends AesImportParams {
length: AesKeyGenLength;
constructor(name: AesType, length: AesKeyGenLength) {
super(name);
this.length = length;
}
override getImportParams() {
return new AesImportParams(this.name);
}
}
export class AesGcmGenParams extends AesKeyGenParams {
constructor() {
super(aesTypes.AES_GCM, 256);
}
}
export class Ed25519KeyGenParams extends Ed25519ImportParams {
override getImportParams() {
return new Ed25519ImportParams();
}
}

View File

@ -0,0 +1,20 @@
export const messageTypes = {
GENERATE_KEYS: "GENERATE_KEYS",
POPUP_IS_OPENED: "POPUP_IS_OPENED",
WAIT_ENTER_PASSWORD: "WAIT_ENTER_PASSWORD",
SELECT_SIGN_KEYS: "SELECT_SIGN_KEYS",
SIGN_DATA: "SIGN_DATA",
VERIFY_DATA: "VERIFY_DATA",
ENCRYPT: "ENCRYPT",
ENGINE_IS_EXIST: "ENGINE_IS_EXIST"
} as const;
export const messageListeners = {
background: "background",
popup: "popup",
} as const;
export const onlyofficeChannels = {
onlyofficeExtensionChannel: "onlyoffice-sign-extension-channel",
onlyofficeClientChannel: "onlyoffice-sign-client-channel",
} as const;

View File

@ -0,0 +1,35 @@
import {messageListeners, messageTypes} from "./message-const.ts";
export type MessagesType = {type: typeof messageTypes[keyof typeof messageTypes]};
export const isMessages = (arg: unknown): arg is MessagesType => {
return !!(arg && typeof arg === "object" && "type" in arg && typeof arg.type === "string" && arg.type in messageTypes);
};
export type DispatchEventMessageType = {
id?: number;
data: MessagesType;
}
export type AnswerMainPageEventType = {
id?: number;
data: unknown;
};
type Listeners = typeof messageListeners[keyof typeof messageListeners];
type ExtensionMessage<T extends Listeners = Listeners> = {
data: MessagesType;
listener: T;
};
export type BackgroundMessage = ExtensionMessage<typeof messageListeners.background>;
export type PopupMessage = ExtensionMessage<typeof messageListeners.popup>;
const isExtensionMessageType = (arg: unknown): arg is ExtensionMessage => {
return !!(arg && typeof arg === "object" && "data" in arg && isMessages(arg.data) && "listener" in arg && typeof arg.listener === "string");
};
export const isBackgroundMessageType = (arg: unknown): arg is BackgroundMessage => {
return isExtensionMessageType(arg) && arg.listener === messageListeners.background;
};
export const isPopupMessageType = (arg: unknown): arg is PopupMessage => {
return isExtensionMessageType(arg) && arg.listener === messageListeners.popup;
};

View File

@ -0,0 +1,29 @@
// @ts-ignore
import {StorageManager} from "../../../key-storage/key-storage.js";
import browser from "webextension-polyfill";
import type {JSONKeyPair} from "./keys/key-types.ts";
function ExtensionStorageManager() {
StorageManager.call(this);
}
ExtensionStorageManager.prototype = Object.create(StorageManager);
ExtensionStorageManager.prototype.constructor = ExtensionStorageManager;
ExtensionStorageManager.prototype.getStorageKeys = function() {
return browser.storage.local.get("keys").then(function(item) {
if (item && Array.isArray(item.keys)) {
return item.keys;
}
return [];
});
};
ExtensionStorageManager.prototype.getMasterPassword = function() {
return browser.storage.local.get("masterPassword").then(function(item) {
return item.masterPassword ? item.masterPassword : null;
});
};
ExtensionStorageManager.prototype.setStorageKeys = function(exportedKeys: JSONKeyPair[]) {
return browser.storage.local.set({keys: exportedKeys});
}
ExtensionStorageManager.prototype.setMasterPasswordWithKeys = function(exportedKeys: JSONKeyPair[]) {
return browser.storage.local.set({keys: exportedKeys});
}

View File

@ -0,0 +1,42 @@
export function ab2str(buf: ArrayBuffer) {
return String.fromCharCode.apply(null, buf);
}
export function ab2base64(buf: ArrayBuffer) {
const str = ab2str(buf);
return btoa(str);
}
export function base642ui(base64: string) {
const str = atob(base64);
return str2ui(str);
}
export function str2ui(str: string) {
const ui = new Uint8Array(str.length);
for (let i = 0; i < str.length; i++) {
ui[i] = str.charCodeAt(i);
}
return ui;
}
export const selectBinary = (callback: (file: File) => void) => {
const input = document.createElement("input");
input.type = "file";
input.accept = "application/octet-stream";
input.addEventListener("change", (e) => {
const target = e.target as HTMLInputElement;
const file = target.files?.[0];
if (file) {
callback(file);
}
});
input.click();
};
export const downloadBinary = (data: Uint8Array) => {
const blob = new Blob([data], {type: "application/octet-stream"});
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = `onlyoffice_keychain_${(new Date()).toISOString()}.bin`;
link.click();
URL.revokeObjectURL(url);
}

View File

@ -0,0 +1,12 @@
import {sendToBackground, sendToPage} from "./messenger.ts";
import {messageTypes, onlyofficeChannels} from "../common/message-const.ts";
import {
type DispatchEventMessageType,
} from "../common/message-types.ts";
window.addEventListener(onlyofficeChannels.onlyofficeExtensionChannel, (event: CustomEvent<DispatchEventMessageType>) => {
sendToBackground(event.detail.data).then((response: unknown) => {
sendToPage({id: event.detail.id, data: response});
});
});
window.dispatchEvent(new CustomEvent<DispatchEventMessageType>(onlyofficeChannels.onlyofficeClientChannel, {detail: {data: {type: messageTypes.ENGINE_IS_EXIST}}}));

View File

@ -0,0 +1,22 @@
import type {
AnswerMainPageEventType,
BackgroundMessage,
MessagesType,
PopupMessage
} from "../common/message-types.ts";
import browser from "webextension-polyfill";
import {messageListeners, onlyofficeChannels} from "../common/message-const.ts";
export const sendToBackground = async (data: MessagesType) => {
const backgroundData: BackgroundMessage = {data, listener: messageListeners.background};
return browser.runtime.sendMessage(backgroundData);
};
export const sendToPopup = async (data: MessagesType) => {
const sendData: PopupMessage = {listener: messageListeners.popup, data};
return browser.runtime.sendMessage(sendData);
};
export const sendToPage = (data: AnswerMainPageEventType) => {
window.dispatchEvent(new CustomEvent<AnswerMainPageEventType>(onlyofficeChannels.onlyofficeClientChannel, {detail: data}));
};

View File

@ -0,0 +1,3 @@
export function Loader() {
return <div>Loading...</div>;
}

View File

@ -0,0 +1,12 @@
type PropsType = {
name: string;
labelText: string;
onChange: (e: string) => void;
}
export default function PasswordInput({onChange, name, labelText}: PropsType) {
return <>
<label htmlFor={name}>{labelText}</label>
<input required={true} minLength={8} onChange={(e) => onChange(e.target.value)} type="password" name={name}/>
</>;
}

View File

@ -0,0 +1,9 @@
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import App from './pages/app/app.tsx'
createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
</StrictMode>,
)

View File

@ -0,0 +1,91 @@
import {useState, useEffect} from 'react'
import Login from "../login/login.tsx";
import {getStorageMasterPassword, initCheckOpenedPopup, setStorageMasterPassword} from "../../../utils/utils.ts";
import {useTaskManager} from "../../../task-manager/task-manager.ts";
import {Dashboard} from "../dashboard/dashboard.tsx";
// @ts-ignore
import {StorageManager} from "../storage-manager/storage-manager.ts";
import {KeyPair} from "../../../../common/keys/keys.ts";
import {Ed25519KeyGenParams} from "../../../../common/keys/params.ts";
import {ChangePasswordPage} from "../change-password/change-password.tsx";
import {locations} from "../../../utils/locations.ts";
import SelectKeysPage from "../select-keys/select-keys.tsx";
import {messageTypes} from "../../../../common/message-const.ts";
const storageManager = new StorageManager();
const generateKeys = async () => {
const key = await storageManager.generateKeys(new Ed25519KeyGenParams());
if (key) {
await storageManager.addNewKeys([key]);
return key;
}
};
export default function App() {
const [localMasterPassword, setLocalMasterPassword] = useState<string | null>(null);
const [keys, setKeys] = useState<KeyPair[]>([]);
const {location, setLocation, promiseRef} = useTaskManager();
useEffect(() => {
(async () => {
const storageMasterPassword = await getStorageMasterPassword();
setLocalMasterPassword(storageMasterPassword);
await storageManager.loadKeysFromStorage();
setKeys(storageManager.getValidKeys());
})();
initCheckOpenedPopup();
}, []);
const handleSelectKey = (e: React.MouseEvent<HTMLLIElement>) => {
if (promiseRef.current) {
const guid = e.currentTarget.dataset.guid;
if (promiseRef.current.messageId === messageTypes.SELECT_SIGN_KEYS && guid) {
promiseRef.current.resolve(guid);
} else {
promiseRef.current.reject("Another task was expected to resolve");
}
}
promiseRef.current = null;
window.close();
};
const handleSubmitMasterPassword = (masterPassword: string) => {
setStorageMasterPassword(masterPassword);
setLocalMasterPassword(masterPassword);
};
const handleSubmitNewMasterPassword = async (newMasterPassword: string) => {
await storageManager.changeMasterPassword(newMasterPassword);
setLocalMasterPassword(newMasterPassword);
setLocation("");
};
const handleGenerateKeys = async () => {
const keyPair = await generateKeys();
if (keyPair) {
setKeys(storageManager.getValidKeys());
}
};
const handleExportKeys = () => {
storageManager.exportKeys();
}
const handleImportKeys = async () => {
storageManager.importKeys(() => {setKeys(storageManager.getValidKeys())});
}
const handleDeprecateKey = async (key: KeyPair) => {
await storageManager.deprecateKey(key);
setKeys(storageManager.getValidKeys());
};
const isLoggedOut = localMasterPassword === null;
return (
<>
{
isLoggedOut ?
<Login handleSubmitMasterPassword={handleSubmitMasterPassword} /> :
location === locations.changeMasterPassword ? <ChangePasswordPage handleSubmitNewMasterPassword={handleSubmitNewMasterPassword} /> :
location === locations.selectKeys ? <SelectKeysPage keys={keys} handleKey={handleSelectKey}/> :
<Dashboard handleDeprecateKey={handleDeprecateKey} changeLocation={setLocation} handleImportKeys={handleImportKeys} handleExportKeys={handleExportKeys} handleGenerateSignKeys={handleGenerateKeys} keys={keys} masterPassword={localMasterPassword}/>
}
</>
)
}

View File

@ -0,0 +1,31 @@
import PasswordInput from "../../components/password-input/password-input.tsx";
import {type FormEvent, useState} from "react";
import {compareWithOldMasterPassword} from "../../../utils/utils.ts";
type ChangePasswordPageProps = {
handleSubmitNewMasterPassword: (newMasterPassword: string) => void;
};
export function ChangePasswordPage({handleSubmitNewMasterPassword}: ChangePasswordPageProps) {
const [oldMasterPassword, setOldMasterPassword] = useState("");
const [newMasterPassword, setNewMasterPassword] = useState("");
const [confirmMasterPassword, setConfirmMasterPassword] = useState("");
const [error, setError] = useState("");
const onSubmit = async (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
const isEqualsOldPassword = await compareWithOldMasterPassword(oldMasterPassword);
if (!isEqualsOldPassword) {
setError("Check if you entered your old password correctly.");
} else if (newMasterPassword !== confirmMasterPassword) {
setError("The new passwords do not match.");
} else {
handleSubmitNewMasterPassword(newMasterPassword);
}
};
return <form onSubmit={onSubmit}>
<PasswordInput name={"old-password"} labelText={"Enter old master password"} onChange={setOldMasterPassword}/>
<PasswordInput name={"new-password"} labelText={"Enter new master password"} onChange={setNewMasterPassword}/>
<PasswordInput name={"confirm-new-password"} labelText={"Confirm new master password"} onChange={setConfirmMasterPassword}/>
{error && <div>{error}</div>}
<button type={"submit"}>Confirm</button>
</form>
}

View File

@ -0,0 +1,8 @@
.wrapper {
display: flex;
justify-content: space-between;
:hover {
background-color: rgba(240 , 240, 240, 255);
}
}

View File

@ -0,0 +1,29 @@
import type {KeyPair} from "../../../../common/keys/keys.ts";
import {locations} from "../../../utils/locations.ts";
import css from "./dashboard.module.css";
type DashboardProps = {
masterPassword: string;
keys: KeyPair[];
handleGenerateSignKeys: () => Promise<void>
handleImportKeys: () => void;
handleExportKeys: () => void;
handleDeprecateKey: (key: KeyPair) => void;
changeLocation: (location: string) => void
};
export function Dashboard({keys, handleDeprecateKey, masterPassword, handleGenerateSignKeys, handleImportKeys, handleExportKeys, changeLocation}: DashboardProps) {
return <div>
<div>Hello, your master password: {masterPassword}</div>
<button onClick={() => {changeLocation(locations.changeMasterPassword)}}>Change password</button>
<button onClick={handleExportKeys}>Export keys</button>
<button onClick={handleImportKeys}>Import keys</button>
<button onClick={handleGenerateSignKeys}>Generate sign keys</button>
<div>Generated sign keys</div>
{keys.map((key, idx) =>
<div key={idx} className={css.wrapper}>
<div>{key.guid}</div>
<div onClick={() => handleDeprecateKey(key)}>&times;</div>
</div>)}
</div>
}

View File

@ -0,0 +1,25 @@
import {type FormEvent, useState} from "react";
import PasswordInput from "../../components/password-input/password-input.tsx";
type LoginProps = {
handleSubmitMasterPassword: (password: string) => void;
};
export default function Login({handleSubmitMasterPassword}: LoginProps) {
const [masterPassword, setMasterPassword] = useState("");
const [confirmMasterPassword, setConfirmMasterPassword] = useState("");
const [error, setError] = useState("");
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (masterPassword === confirmMasterPassword) {
handleSubmitMasterPassword(masterPassword);
} else {
setError("The passwords don't match");
}
};
return <form onSubmit={handleSubmit}>
<PasswordInput name={"login-password"} labelText={"Enter new master password"} onChange={setMasterPassword}/>
<PasswordInput name={"login-confirm-password"} labelText={"Confirm new master password"} onChange={setConfirmMasterPassword}/>
{error && <div>{error}</div>}
<button type={"submit"}>Confirm</button>
</form>
};

View File

@ -0,0 +1,6 @@
.key {
cursor: pointer;
&:hover {
background-color: rgba(0, 0, 0, 10%);
}
}

View File

@ -0,0 +1,16 @@
import type {KeyPair} from "../../../../common/keys/keys.ts";
import type {MouseEventHandler} from "react";
import css from "./select-keys.module.css";
type TSelectKeysProps = {
keys: KeyPair[];
handleKey: MouseEventHandler<HTMLLIElement>;
};
export default function SelectKeysPage({keys, handleKey}: TSelectKeysProps) {
return <ul>
{keys.map((key) => <li className={css.key} key={key.guid} data-guid={key.guid} onClick={handleKey}>
{key.guid}
</li>)}
</ul>
};

View File

@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/popup/App/main.tsx"></script>
</body>
</html>

View File

@ -0,0 +1,46 @@
import browser from "webextension-polyfill";
import {isPopupMessageType} from "../../common/message-types.ts";
import {messageTypes} from "../../common/message-const.ts";
import {isStorageLogged, selectSignKeys} from "./tasks.ts";
import {useEffect, useRef, useState} from "react";
type TSelectKeysPromise = {
resolve: (guid: string) => void;
messageId: typeof messageTypes.SELECT_SIGN_KEYS
};
type TPromiseArgs = {
reject: (error: string) => void;
} & (TSelectKeysPromise);
export type TPromiseRef = (newResolve: TPromiseArgs["resolve"], newReject: TPromiseArgs["reject"], id: TPromiseArgs["messageId"]) => void;
export const useTaskManager = () => {
const [location, setLocation] = useState("");
const promiseRef = useRef<TPromiseArgs | null>(null);
const setPromiseRef: TPromiseRef = (newResolve, newReject, id) => {
if (promiseRef.current) {
promiseRef.current.reject("Another task has been selected");
}
promiseRef.current = {resolve: newResolve, reject: newReject, messageId: id};
}
useEffect(() => {
const listener = (message: unknown) => {
if (!isPopupMessageType(message)) {
return false;
}
const data = message.data;
switch (data.type) {
case messageTypes.WAIT_ENTER_PASSWORD: {
return isStorageLogged();
}
case messageTypes.SELECT_SIGN_KEYS: {
return selectSignKeys(setLocation, setPromiseRef);
}
}
return false;
};
browser.runtime.onMessage.addListener(listener);
return () => {
browser.runtime.onMessage.removeListener(listener);
}
}, []);
return {location, setLocation, promiseRef};
};

View File

@ -0,0 +1,16 @@
import {checkIsStorageLogged} from "../utils/utils.ts";
import {locations} from "../utils/locations.ts";
import {messageTypes} from "../../common/message-const.ts";
import type {TPromiseRef} from "./task-manager.ts";
export const isStorageLogged = async () => {
await checkIsStorageLogged();
return true;
};
export const selectSignKeys = (setNavigation: (location: string) => void, setPromiseRef: TPromiseRef): Promise<string> => {
setNavigation(locations.selectKeys);
return new Promise((resolve, reject) => {
setPromiseRef(resolve, reject, messageTypes.SELECT_SIGN_KEYS);
});
}

View File

@ -0,0 +1,4 @@
export const locations = {
changeMasterPassword: "changeMasterPassword",
selectKeys: "selectKeys",
} as const;

View File

@ -0,0 +1,38 @@
import browser from "webextension-polyfill";
export const getStorageMasterPassword = async () => {
const masterPassword = await browser.storage.local.get('masterPassword');
if (masterPassword && typeof masterPassword.masterPassword === 'string') {
return masterPassword.masterPassword;
}
return null;
}
export const compareWithOldMasterPassword = async (checkPassword: string) => {
const masterPassword = await getStorageMasterPassword();
return masterPassword === checkPassword;
}
export const setStorageMasterPassword = (masterPassword: string) => {
browser.storage.local.set({masterPassword});
}
export const checkIsStorageLogged = async () => {
const masterPassword = await getStorageMasterPassword();
if (masterPassword) {
return true;
}
return getChangedProperty("masterPassword");
};
const getChangedProperty = (key: string) => {
return new Promise((resolve) => {
browser.storage.local.onChanged.addListener(function handler(change) {
if (change[key]) {
browser.storage.local.onChanged.removeListener(handler);
resolve(change[key].newValue);
}
});
});
};
export const initCheckOpenedPopup = () => {
const port = browser.runtime.connect({ name: "popup" });
port.postMessage({ opened: true });
};

View File

@ -0,0 +1,7 @@
export {};
declare global {
interface WindowEventMap {
"onlyoffice-sign-extension-channel": CustomEvent;
}
}

View File

@ -0,0 +1 @@
/// <reference types="vite/client" />

View File

@ -0,0 +1,29 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "ES2022",
"useDefineForClassFields": true,
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"moduleDetection": "force",
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"erasableSyntaxOnly": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true,
"noImplicitOverride": true,
"resolveJsonModule": true
},
"include": ["src"]
}

View File

@ -0,0 +1,7 @@
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
}

View File

@ -0,0 +1,25 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"target": "ES2023",
"lib": ["ES2023"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"moduleDetection": "force",
"noEmit": true,
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"erasableSyntaxOnly": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["vite.config.ts"]
}

View File

@ -0,0 +1,12 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import {crx} from "@crxjs/vite-plugin";
import manifest from "./manifest.config.ts";
// https://vite.dev/config/
export default defineConfig({
plugins: [crx({ manifest }), react()],
build: {
sourcemap: 'inline'
}
})

View File

@ -0,0 +1,11 @@
# Crypto library
## Information for development
1. Run ```npm run dev``` in the library directory to develop the library in watch mode.
2. Run ```npm link``` in the library directory.
3. Run ```npm link crypto-library``` in the directory where the library is required as a npm module.
## Information for build
Run ```npm run build``` in the library directory to build the library as ```es``` and ```iife``` modules.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,14 @@
{
"name": "key-storage",
"version": "1.0.0",
"main": "dist/key-storage.es.js",
"files": ["dist"],
"devDependencies": {
"vite": "^7.3.0"
},
"scripts": {
"dev": "vite build --watch",
"build": "vite build",
"preview": "vite preview"
}
}

View File

@ -0,0 +1,142 @@
import {EncryptData, WebEncryptKeyPair, WebSignKeyPair, WebSymmetricKey} from "./keys";
import {AesGcmKeyGenParams, PBKDF2Params} from "./params";
import {c_oAscExportKeyFormat} from "./defines";
import {BinaryWriter} from "./serialize/writer";
import {initClass} from "./utils";
function CCryptoBase() {
}
CCryptoBase.prototype.sign = function(key, data) {};
CCryptoBase.prototype.digest = function(algorithm, data) {};
CCryptoBase.prototype.verify = function(key, signature, data) {};
CCryptoBase.prototype.decrypt = function(key, data) {};
CCryptoBase.prototype.encrypt = function(key, data) {};
CCryptoBase.prototype.generateKey = function(params) {};
CCryptoBase.prototype.getRandomValues = function(length) {};
CCryptoBase.prototype.randomUUID = function() {};
CCryptoBase.prototype.initKey = function(key, masterPassword) {return Promise.resolve()};
CCryptoBase.prototype.getAesKey = function(key, pbkdfParams) {return Promise.resolve()};
function CWebCrypto() {
CCryptoBase.call(this);
this.crypto = self.crypto;
this.subtle = this.crypto.subtle;
}
initClass(CWebCrypto, CCryptoBase);
CWebCrypto.prototype.getRandomValues = function(length) {
const ui = new Uint8Array(length);
return this.crypto.getRandomValues(ui);
}
CWebCrypto.prototype.getAesKey = function(masterPassword, pbkdfParams) {
const oThis = this;
const aesKeyGenParams = new AesGcmKeyGenParams();
return this.subtle.importKey(
'raw',
masterPassword,
{ name: 'PBKDF2' },
false,
['deriveKey']
).then(function(pwKey) {
return oThis.subtle.deriveKey(
pbkdfParams.getCryptoParams(),
pwKey,
aesKeyGenParams.getKeyGenCryptoParams(),
false,
['encrypt', 'decrypt']
);
}).then(function(aesKey) {
return WebSymmetricKey.fromCryptoKey(aesKey, aesKeyGenParams.getImportParams());
});
};
CWebCrypto.prototype.sign = function(key, data) {
const oThis = this;
const cryptoKey = key.getCryptoKey();
const params = key.getCryptoParams();
return oThis.subtle.sign(cryptoKey, cryptoKey, data);
}
CWebCrypto.prototype.digest = function(algorithm, data) {
return this.subtle.digest(algorithm, data);
}
CWebCrypto.prototype.verify = function(key, signature, data) {
const oThis = this;
const cryptoKey = key.getCryptoKey();
return oThis.subtle.verify(key.params, cryptoKey, signature, data);
}
CWebCrypto.prototype.decrypt = function(key, data) {
const oThis = this;
const cryptoKey = key.getCryptoKey();
const encryptParams = data.getEncryptParams();
const algorithm = encryptParams.getCryptoParams();
return oThis.subtle.decrypt(algorithm, cryptoKey, data.getEncryptData()).then(function(data) {
return new Uint8Array(data);
});
}
CWebCrypto.prototype.encrypt = function(key, data) {
const cryptoKey = key.getCryptoKey();
const encryptParams = key.getEncryptParams();
const algorithm = encryptParams.getCryptoParams();
return this.subtle.encrypt(algorithm, cryptoKey, data).then(function (encryptedData) {
const encryptData = new EncryptData(encryptedData, encryptParams);
return encryptData.export();
});
}
CWebCrypto.prototype.exportKey = function(key) {
const cryptoKey = key.getCryptoKey();
const format = key.getCryptoFormat();
return this.subtle.exportKey(format, cryptoKey);
}
CWebCrypto.prototype.generateKey = function(params, aesKey) {
const oThis = this;
const cryptoParams = params.getKeyGenCryptoParams();
const cryptoUsages = params.getCryptoUsages();
let saveCryptoKey;
return this.subtle.generateKey(cryptoParams, true, cryptoUsages).then(function(cryptoKey) {
saveCryptoKey = cryptoKey;
if (cryptoKey.privateKey && cryptoKey.publicKey) {
const publicKey = oThis.subtle.exportKey(c_oAscExportKeyFormat.spki, cryptoKey.publicKey);
const privateKey = oThis.subtle.exportKey(c_oAscExportKeyFormat.pkcs8, cryptoKey.privateKey).then(function(data) {
return aesKey.encrypt(data);
});
return Promise.all([publicKey, privateKey]);
}
return oThis.subtle.exportKey(c_oAscExportKeyFormat.raw, cryptoKey).then(function (data) {
return aesKey.encrypt(data);
});
}).then(function(exportedKeys) {
const importParams = params.getImportParams();
if (Array.isArray(exportedKeys)) {
const publicKeyBuffer = exportedKeys[0];
const privateKeyBuffer = exportedKeys[1];
if (params.isSign()) {
return WebSignKeyPair.fromWebCrypto(publicKeyBuffer, saveCryptoKey.publicKey, privateKeyBuffer, saveCryptoKey.privateKey, importParams);
}
return WebEncryptKeyPair.fromWebCrypto(publicKeyBuffer, saveCryptoKey.publicKey, privateKeyBuffer, saveCryptoKey.privateKey, importParams);
} else {
return WebSymmetricKey.fromWebCrypto(exportedKeys, saveCryptoKey, importParams);
}
});
};
CWebCrypto.prototype.randomUUID = function() {
return this.crypto.randomUUID();
}
CWebCrypto.prototype.initKey = function (key, aesKey) {
const binaryKey = key.getBinaryKey();
const oThis = this;
let binaryKeyPromise;
if (aesKey) {
binaryKeyPromise = aesKey.decrypt(binaryKey);
} else {
binaryKeyPromise = Promise.resolve(binaryKey);
}
return binaryKeyPromise.then(function(binaryCryptoData) {
return oThis.subtle.importKey(key.getImportFormat(), binaryCryptoData, key.getImportCryptoParams(), true, key.getCryptoUsages());
}).then(function (cryptoKey) {
key.setCryptoKey(cryptoKey);
});
};
export function getCrypto() {
return new CWebCrypto();
}

View File

@ -0,0 +1,45 @@
export const c_oAscDigestType = {
SHA1: 1,
SHA256: 2,
SHA384: 3,
SHA512: 4
};
export const c_oAscCryptoDigestType = {};
c_oAscCryptoDigestType[c_oAscDigestType.SHA1] = "SHA-1";
c_oAscCryptoDigestType[c_oAscDigestType.SHA256] = "SHA-256";
c_oAscCryptoDigestType[c_oAscDigestType.SHA384] = "SHA-384";
c_oAscCryptoDigestType[c_oAscDigestType.SHA512] = "SHA-512";
export const c_oAscExportKeyFormat = {
pkcs8: "pkcs8",
spki: "spki",
raw: "raw"
};
export const c_oAscKeyStorageType = {
NoType: 0,
WebSymmetricKey: 1,
WebSignKeyPair: 2,
WebEncryptKeyPair: 3,
Ed25519ImportParams: 6,
EncryptData: 7,
RSAOAEPImportParams: 8,
RSAOAEPKeyGenParams: 9,
Ed25519KeyGenParams: 10,
AesGCMCryptoParams: 11,
AesGCMKeyGenParams: 12,
PBKDF2Params: 14,
WebPrivateSignKey: 15,
WebPrivateEncryptKey: 16,
WebPublicSignKey: 17,
WebPublicEncryptKey: 18,
RsaOAEPCryptoParams: 19
};
export const c_oAscCryptoRsaType = {};
c_oAscCryptoRsaType[c_oAscKeyStorageType.RSAOAEPKeyGenParams] = "RSA-OAEP";
c_oAscCryptoRsaType[c_oAscKeyStorageType.RSAOAEPImportParams] = "RSA-OAEP";
export const c_oAscCryptoAesType = {};
c_oAscCryptoAesType[c_oAscKeyStorageType.AesGCMKeyGenParams] = "AES-GCM";

View File

@ -0,0 +1,34 @@
import {c_oAscKeyStorageType} from "./defines";
import {
EncryptData,
WebEncryptKeyPair, WebPrivateEncryptKey,
WebPrivateSignKey, WebPublicEncryptKey,
WebPublicSignKey,
WebSignKeyPair,
WebSymmetricKey
} from "./keys";
import {
AesGcmCryptoParams, AesGcmKeyGenParams,
Ed25519ImportParams,
Ed25519KeyGenParams, PBKDF2Params, RsaOAEPCryptoParams,
RsaOAEPImportParams,
RsaOAEPKeyGenParams
} from "./params";
export const c_oAscObjectFactory = {};
c_oAscObjectFactory[c_oAscKeyStorageType.WebSymmetricKey] = WebSymmetricKey;
c_oAscObjectFactory[c_oAscKeyStorageType.WebSignKeyPair] = WebSignKeyPair;
c_oAscObjectFactory[c_oAscKeyStorageType.WebEncryptKeyPair] = WebEncryptKeyPair;
c_oAscObjectFactory[c_oAscKeyStorageType.Ed25519ImportParams] = Ed25519ImportParams;
c_oAscObjectFactory[c_oAscKeyStorageType.EncryptData] = EncryptData;
c_oAscObjectFactory[c_oAscKeyStorageType.RSAOAEPImportParams] = RsaOAEPImportParams;
c_oAscObjectFactory[c_oAscKeyStorageType.RSAOAEPKeyGenParams] = RsaOAEPKeyGenParams;
c_oAscObjectFactory[c_oAscKeyStorageType.Ed25519KeyGenParams] = Ed25519KeyGenParams;
c_oAscObjectFactory[c_oAscKeyStorageType.AesGCMCryptoParams] = AesGcmCryptoParams;
c_oAscObjectFactory[c_oAscKeyStorageType.AesGCMKeyGenParams] = AesGcmKeyGenParams;
c_oAscObjectFactory[c_oAscKeyStorageType.PBKDF2Params] = PBKDF2Params;
c_oAscObjectFactory[c_oAscKeyStorageType.WebPrivateSignKey] = WebPrivateSignKey;
c_oAscObjectFactory[c_oAscKeyStorageType.WebPrivateEncryptKey] = WebPrivateEncryptKey;
c_oAscObjectFactory[c_oAscKeyStorageType.WebPublicSignKey] = WebPublicSignKey;
c_oAscObjectFactory[c_oAscKeyStorageType.WebPublicEncryptKey] = WebPublicEncryptKey;
c_oAscObjectFactory[c_oAscKeyStorageType.RsaOAEPCryptoParams] = RsaOAEPCryptoParams;

Some files were not shown because too many files have changed in this diff Show More