Compare commits

...
1949 Commits
Author SHA1 Message Date
antelle 2c386e67e2 plugin settings 2021-07-04 20:54:59 +02:00
antelle b572876099 global shortcuts 2021-07-04 17:12:28 +02:00
antelle 48c4f28d5d settings 2021-07-04 16:01:34 +02:00
antelle 8df3899920 advanced settings 2021-07-04 14:35:54 +02:00
antelle f9a79bf2c4 general settings 2021-07-04 14:02:43 +02:00
antelle 809dd897f7 settings scrolling 2021-07-04 13:15:19 +02:00
antelle 8d2e5b12aa fixed storage logout 2021-07-04 13:05:42 +02:00
antelle d5a61acd01 settings 2021-07-04 13:02:48 +02:00
antelle aa11e1a65e settings general pages 2021-07-03 21:55:11 +02:00
antelle 839afdda36 storage listing 2021-07-03 20:22:54 +02:00
antelle 40b85c76fb storage file listing 2021-07-03 20:05:28 +02:00
antelle da8ba46d21 icon style fix 2021-06-19 13:03:57 +02:00
antelle b15fd7258d icon selection 2021-06-19 12:49:16 +02:00
antelle 701d593b5b math.div sass migration 2021-06-19 11:50:37 +02:00
antelle c8ad6c8416 grp 2021-06-17 22:36:51 +02:00
antelle b859daf39b up deps 2021-06-17 22:36:10 +02:00
antelle d2d58e675a removed test code 2021-06-14 21:09:38 +02:00
antelle 518b34873b auto-type hint 2021-06-14 21:08:55 +02:00
antelle 763ee2e1f5 group 2021-06-14 07:25:29 +02:00
antelle 9dd8ee05e9 eslint 2021-06-13 12:03:03 +02:00
antelle b4a49e2321 generator presets 2021-06-13 12:02:46 +02:00
antelle 04c2f487fc tag panel 2021-06-13 10:34:44 +02:00
antelle 708ac26837 panel mode 2021-06-13 10:11:45 +02:00
antelle 9431a1bbf5 generator presets link 2021-06-12 22:22:08 +02:00
antelle 006e841a84 ci linting 2021-06-12 21:18:49 +02:00
antelle 7a9a16ce0e eslint 2021-06-12 21:14:05 +02:00
antelle 342242b2c3 about 2021-06-12 20:52:39 +02:00
antelle 06ece835c7 generator fix 2021-06-12 20:40:23 +02:00
antelle 78f322b51a moved some models 2021-06-12 20:39:01 +02:00
antelle 88b25a54cb generator fix 2021-06-12 20:15:55 +02:00
antelle 638b1a9aac menu fix 2021-06-12 20:14:19 +02:00
antelle e526d0e3f0 fixed double context menu 2021-06-12 17:16:05 +02:00
antelle 75da650a80 footer generator shortcut 2021-06-12 16:36:16 +02:00
antelle 8a9243b639 fix 2021-06-12 16:32:21 +02:00
antelle 2baf2b0dcf hide menu on any key 2021-06-12 16:30:25 +02:00
antelle ec126d52e2 fixed list sorting 2021-06-12 16:23:23 +02:00
antelle 3c2cab94d7 list context menu 2021-06-12 16:19:19 +02:00
antelle 12dea11a9a generator 2021-06-12 13:47:00 +02:00
antelle bf0192412a Model.reset 2021-06-12 10:01:19 +02:00
antelle acad35a52b fixed displaying first item 2021-06-06 15:54:37 +02:00
antelle 671212c23d eslint 2021-06-06 10:22:42 +02:00
antelle 146de47e0c list size calculation 2021-06-06 10:21:17 +02:00
antelle 7187cc5e1d fixed list jitter 2021-06-06 10:18:24 +02:00
antelle 0a656830c8 tooltip fixes 2021-06-05 23:42:46 +02:00
antelle 8142025fdd filtering 2021-06-05 22:39:03 +02:00
antelle 98b78b3856 item height 2021-06-05 22:05:23 +02:00
antelle 5140d729e2 scrolling 2021-06-05 21:15:44 +02:00
antelle 3a4b1f56d9 scrolling 2021-06-05 20:14:56 +02:00
antelle bd5d8bded9 list search 2021-06-05 18:39:49 +02:00
antelle ee6c96cdc8 modular lodash 2021-06-02 22:00:45 +02:00
antelle 720118c5df menu filters 2021-06-01 23:58:32 +02:00
antelle 3ec6e2f8e8 removed a prop 2021-06-01 22:03:40 +02:00
antelle af540cf250 settings about and help 2021-06-01 21:30:21 +02:00
antelle d9ed7ced22 settings menu 2021-06-01 20:35:34 +02:00
antelle 61a78107c4 settings page 2021-06-01 20:01:04 +02:00
antelle 3de2f1d25d query 2021-06-01 18:31:32 +02:00
antelle e0fa3e18d1 query 2021-06-01 17:57:29 +02:00
antelle 3e49fc4c75 file backups 2021-06-01 17:10:30 +02:00
antelle 6fe9d56b3c settings mode 2021-05-31 23:48:30 +02:00
antelle 32126939a6 sync 2021-05-31 22:25:03 +02:00
antelle 7962631a03 OpenParams 2021-05-30 22:53:01 +02:00
antelle 10dc9a4528 fixed open 2021-05-30 22:49:42 +02:00
antelle e93cdae808 cleanup 2021-05-30 22:22:23 +02:00
antelle cd9ba11d24 logging modals 2021-05-30 22:21:53 +02:00
antelle f7d6802f58 opening files 2021-05-30 22:18:38 +02:00
antelle b1b1911eba open 2021-05-30 16:26:14 +02:00
antelle d2536d8dcd displaying an import error 2021-05-29 22:32:11 +02:00
antelle 500eaa4569 tests tsconfig 2021-05-29 22:12:28 +02:00
antelle 6f068ebf18 better tests compatibility 2021-05-29 22:04:59 +02:00
antelle f840f7b15d local file alert 2021-05-29 21:40:20 +02:00
antelle c172477004 rename 2021-05-29 21:31:22 +02:00
antelle 9e76878c7c xml 2021-05-29 20:12:31 +02:00
antelle 06fef55e2c drag-drop 2021-05-29 19:29:39 +02:00
antelle 0ce5fc462a eslint 2021-05-29 16:22:45 +02:00
antelle 40dd3637d7 open screen progress 2021-05-29 16:16:16 +02:00
antelle caa17a48a8 open idle 2021-05-29 08:59:58 +02:00
antelle 2fe980f2ab open view split 2021-05-28 23:16:14 +02:00
antelle 0b38897868 password focus 2021-05-28 20:10:07 +02:00
antelle f3a7f75be3 moved a variable 2021-05-28 19:50:13 +02:00
antelle 0bf3c0d43f useKey hook 2021-05-28 19:38:29 +02:00
antelle 6a25732a9f simplified code 2021-05-28 17:37:39 +02:00
antelle 117955bcf9 removed a manifest check 2021-05-28 17:17:48 +02:00
antelle 95d2731d13 list wrap 2021-05-28 17:08:18 +02:00
antelle f7da54dded plugins 2021-05-28 16:42:00 +02:00
antelle 87aebe9216 plugins 2021-05-28 15:51:20 +02:00
antelle 6bc140e123 plugin vars 2021-05-28 14:28:13 +02:00
antelle 4897f9e41e plugin gallery 2021-05-28 13:20:25 +02:00
antelle 4a7797df6c menu selection 2021-05-28 11:56:33 +02:00
antelle f438ed6d54 cleanup 2021-05-28 11:47:08 +02:00
antelle 9230389a91 moved a component 2021-05-28 11:44:06 +02:00
antelle 9857f818ca dragging 2021-05-28 11:43:10 +02:00
antelle c6bc6b059e cleanup 2021-05-28 09:24:31 +02:00
antelle 7556ebf974 scroll 2021-05-28 09:22:17 +02:00
antelle 2591b22f35 readonly 2021-05-27 23:14:01 +02:00
antelle 748c70cd0f optimized id generation a bit 2021-05-27 23:13:33 +02:00
antelle d0a6791f21 id 2021-05-27 21:54:55 +02:00
antelle 8beef89250 fix 2021-05-27 21:50:46 +02:00
antelle b5a19b0186 properly destroying nodes 2021-05-27 21:50:30 +02:00
antelle b530f6d29a shortcuts 2021-05-27 21:40:48 +02:00
antelle d71b7d2f3d menu improvements 2021-05-27 21:33:27 +02:00
antelle 170f50f6fc menu 2021-05-27 20:57:27 +02:00
antelle d01aebe484 alerts fix 2021-05-27 18:50:11 +02:00
antelle 881ffa115e todo 2021-05-27 17:48:17 +02:00
antelle 9cc9958bdf footer 2021-05-27 17:39:19 +02:00
antelle 16d2bd6786 opening demo 2021-05-27 17:13:44 +02:00
antelle 1e607d30e6 open-view 2021-05-27 16:58:27 +02:00
antelle 1923234ffa secure-input 2021-05-27 16:05:15 +02:00
antelle 7a25b0fd39 mode 2021-05-27 14:38:14 +02:00
antelle 1dbf647b1b open view 2021-05-27 14:37:36 +02:00
antelle 0b3b49189f eslint 2021-05-27 14:06:03 +02:00
antelle 73b8ae6431 fix 2021-05-27 14:04:23 +02:00
antelle 4402db826d alerts 2021-05-27 14:03:07 +02:00
antelle 95078ea2f1 renamed localized-with 2021-05-27 12:10:38 +02:00
antelle b270ad52b4 titlebar 2021-05-27 12:09:21 +02:00
antelle 810f785a1f app-view 2021-05-27 09:51:42 +02:00
antelle 8f5e19b64b workspace 2021-05-27 09:42:49 +02:00
antelle 3017b39e5f file-info 2021-05-26 09:33:49 +02:00
antelle c2ad509283 disabled input 2021-05-25 22:45:38 +02:00
antelle 540c607527 secure-input 2021-05-25 22:35:25 +02:00
antelle 17d51ee5f1 yubikey 2021-05-25 21:26:50 +02:00
antelle 522e356fe3 filter 2021-05-25 20:25:53 +02:00
antelle 5c0756855a kdbx-to-html 2021-05-25 19:56:23 +02:00
antelle 38466f934f version 2021-05-25 18:51:27 +02:00
antelle c198e634d4 release notes 2021-05-25 18:51:12 +02:00
antelle 45e1f87d07 file, group, entry 2021-05-25 18:44:53 +02:00
antelle 89f3741f17 cleanup 2021-05-25 08:57:04 +02:00
antelle dba37cc40a locale 2021-05-25 08:56:21 +02:00
antelle a2c3d13bc4 cleanup 2021-05-25 08:32:14 +02:00
antelle c576b52b97 optional 2021-05-25 08:24:05 +02:00
antelle 4234cf5de6 optional field 2021-05-25 08:23:44 +02:00
antelle b7cd6e97e4 added FileStorageExtraOptions 2021-05-25 08:23:28 +02:00
antelle 03cf6c0d50 removed a weird module 2021-05-25 08:20:01 +02:00
antelle 9658535f15 fullscreen 2021-05-24 23:53:53 +02:00
antelle 3c30f1519e extracted window-class 2021-05-24 23:48:44 +02:00
antelle afbf0f369f storage 2021-05-24 23:42:08 +02:00
antelle 4527de78f0 fixed file init 2021-05-24 22:54:59 +02:00
antelle 0dd453e0e2 better model init 2021-05-24 22:51:33 +02:00
antelle bdb7ce22c0 chalresp 2021-05-24 22:46:23 +02:00
antelle 1c7a41ad4f backup 2021-05-24 22:43:20 +02:00
antelle 42126fa5a9 file-info 2021-05-24 22:37:34 +02:00
antelle 9baf47cd6d menu 2021-05-24 22:26:27 +02:00
antelle f25353135d menu 2021-05-24 22:26:04 +02:00
antelle f5d2936594 fix 2021-05-24 18:57:12 +02:00
antelle 8be52aee53 config-loader 2021-05-24 18:49:45 +02:00
antelle 0306f604aa logger.info 2021-05-24 18:03:06 +02:00
antelle 04789ecc22 rename 2021-05-24 18:02:02 +02:00
antelle c55aceb937 logger debug 2021-05-24 18:01:26 +02:00
antelle b8363a53f3 updater 2021-05-24 17:51:24 +02:00
antelle 372acf88b1 simplified code 2021-05-24 16:43:32 +02:00
antelle 4d7336ddec extracted PropertiesOfType 2021-05-24 16:41:26 +02:00
antelle d85cf24f8a improved runtime-data 2021-05-24 16:37:41 +02:00
antelle f64c146d2c moved some components 2021-05-24 16:06:09 +02:00
antelle a83e035ac8 renamed some events 2021-05-24 14:00:35 +02:00
antelle 520438814c cleanup 2021-05-24 13:47:07 +02:00
antelle f716fe50de tip 2021-05-24 13:19:50 +02:00
antelle 6a7df2444d rename 2021-05-24 10:01:25 +02:00
antelle 89c644a1c4 readme 2021-05-23 08:27:33 +02:00
antelle 02a505e2f9 webpack 2021-05-23 08:25:01 +02:00
antelle b46533d243 non-enumerable emitter 2021-05-23 01:02:30 +02:00
antelle 76ed537d61 bootstrap 2021-05-23 00:51:37 +02:00
antelle 6da998f13a views 101 2021-05-23 00:12:02 +02:00
antelle c8a854b60c rename 2021-05-22 23:32:29 +02:00
antelle 582211dde7 cleanup 2021-05-22 22:54:13 +02:00
antelle 9ee4ed6ef9 storage 2021-05-22 22:46:46 +02:00
antelle ee11875459 storage 2021-05-22 17:39:10 +02:00
antelle fb973e3021 storage 2021-05-21 10:08:18 +02:00
antelle bbbef70984 storage oauth listener 2021-05-20 09:53:32 +02:00
antelle ba043e09e9 html-renderer 2021-05-20 09:30:31 +02:00
antelle 84df59498a pkce 2021-05-20 09:13:14 +02:00
antelle 7e3f134024 io-cache 2021-05-20 08:54:28 +02:00
antelle 1eb354a322 kdbxweb-init 2021-05-19 20:48:42 +02:00
antelle 826c761dc6 some restructure 2021-05-19 19:18:31 +02:00
antelle 14b2d10e17 moved desktop-ipc 2021-05-19 17:57:42 +02:00
antelle 404dd1baff qr reader 2021-05-19 17:37:43 +02:00
antelle 19e79187fc app rights checker 2021-05-19 17:08:21 +02:00
antelle bf9f81b80b test 2021-05-19 16:09:57 +02:00
antelle ae1f141b63 deleted a class 2021-05-19 15:49:04 +02:00
antelle 971cee45a0 transport 2021-05-19 15:47:36 +02:00
antelle 0a7e285188 shortcuts 2021-05-19 14:07:29 +02:00
antelle 0047b54f50 some refactoring 2021-05-19 13:06:07 +02:00
antelle 8692aed447 restructured files 2021-05-19 12:26:44 +02:00
antelle 52cef043e1 merge fix 2021-05-19 10:44:18 +02:00
antelle 5c9f4c042e Merge branch 'develop' into ts
# Conflicts:
#	app/scripts/comp/launcher/launcher-electron.js
2021-05-19 10:44:03 +02:00
antelle 47b19d1d74 Merge branch 'master' into develop 2021-05-19 10:42:24 +02:00
antelle 070573e68a Merge branch 'release-1.18'
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
2021-05-19 10:35:35 +02:00
antelle 946d7769f1 bump version 2021-05-19 10:33:41 +02:00
antelle f0426a3ec2 fix #1820: minimize on close on macOS 2021-05-19 10:33:17 +02:00
antelle b2d67818a8 fix #1818: extension connection error if browser cannot be identified 2021-05-19 10:16:40 +02:00
antelle c0b159d824 fix #1824: saving KDBX3 files with compression disabled 2021-05-19 10:07:59 +02:00
antelle 1c5be170c5 more components 2021-05-19 09:57:47 +02:00
antelle a0ec451696 more components 2021-05-19 08:58:34 +02:00
antelle a97897ce6f native modules 2021-05-18 23:22:41 +02:00
antelle f431951ec5 alerts 2021-05-18 23:22:28 +02:00
antelle 5a0389444a logging 2021-05-16 23:04:56 +02:00
antelle 52d10b279f export-api 2021-05-16 23:03:26 +02:00
antelle 10f52c9027 runtime data model 2021-05-16 22:56:50 +02:00
antelle 5a8d0f47a3 stricter checking 2021-05-16 15:22:52 +02:00
antelle c66ce36d70 date-format 2021-05-16 15:06:45 +02:00
antelle dfb4859007 settings-manager 2021-05-16 15:04:02 +02:00
antelle cb79552103 idle-tracker 2021-05-16 14:45:40 +02:00
antelle b2846d0a29 feature tester 2021-05-16 14:41:16 +02:00
antelle 55844451f2 theme watcher 2021-05-16 14:32:06 +02:00
antelle 743cba7538 removed supported flags from launcher 2021-05-16 14:26:41 +02:00
antelle 2fb58ebb27 more code style 2021-05-16 14:25:03 +02:00
antelle a68874bc34 enforcing code style 2021-05-16 14:15:21 +02:00
antelle cc12720856 more checks 2021-05-16 13:57:39 +02:00
antelle 1659103ab8 better types 2021-05-16 13:55:56 +02:00
antelle 22994253c5 changed desktop-ipc location 2021-05-16 13:33:34 +02:00
antelle 52da7649e1 changed a symlink 2021-05-16 13:32:15 +02:00
antelle 8ea3502d8e setting deletion 2021-05-16 13:22:13 +02:00
antelle cabe9e3ae7 storage tests fix 2021-05-16 13:14:02 +02:00
antelle 7af9556d59 app settings 2021-05-16 11:30:44 +02:00
antelle e5ef7ea065 removed a cast 2021-05-15 23:24:09 +02:00
antelle 49f82746a8 cleanup 2021-05-15 23:23:07 +02:00
antelle e086cf392b settings store 2021-05-15 23:21:02 +02:00
antelle 8e45ffbddc launcher 2021-05-15 22:51:06 +02:00
antelle 7bb59fed76 checking batch set without listeners 2021-05-15 20:41:42 +02:00
antelle a8e1665214 derived model events support 2021-05-15 20:37:54 +02:00
antelle 3c4604595a signature verifier test 2021-05-15 17:33:03 +02:00
antelle fbc4cab3a8 -jquery 2021-05-15 17:10:21 +02:00
antelle e8e1f3cc70 moved eslint-disable closer 2021-05-15 17:03:12 +02:00
antelle b990a087a1 removed eslint-disable 2021-05-15 16:59:09 +02:00
antelle 84ac7568ee fix eslint 2021-05-15 16:54:04 +02:00
antelle 093f6e7e25 records 2021-05-15 16:34:56 +02:00
antelle 849ae772e2 moved model 2021-05-15 16:26:31 +02:00
antelle 2fd0bf4339 model 2021-05-15 16:13:05 +02:00
antelle 68ce33c34b events 2021-05-14 23:29:17 +02:00
antelle 882c730738 modules 2021-05-14 23:25:44 +02:00
antelle 55ad94bbb9 todo-ts 2021-05-14 23:22:30 +02:00
antelle 54870ab8fd cleanup 2021-05-14 23:21:38 +02:00
antelle edc32041fd package-lock 2021-05-14 21:20:01 +02:00
antelle 4b6c8876e7 Merge branch 'develop' into ts
# Conflicts:
#	package-lock.json
#	package.json
2021-05-14 21:19:28 +02:00
antelle d7e11e20c1 Merge branch 'master' into develop 2021-05-14 21:18:46 +02:00
antelle d590318153 Merge branch 'release-1.18'
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
2021-05-14 21:02:12 +02:00
antelle 5816ca9c4d bump version 2021-05-14 21:01:43 +02:00
antelle 6627e8c0ec fix #1817: crash on files with large attachments as KDBX3 2021-05-14 21:00:43 +02:00
antelle 379e28e8a4 about version in the the bug report template 2021-05-14 20:56:48 +02:00
antelle 6cdca3af38 ignored an inspection 2021-05-14 19:09:09 +02:00
antelle 27b8633bc2 improved locale 2021-05-14 18:50:45 +02:00
antelle a035796503 signature verifier tests 2021-05-13 23:59:20 +02:00
antelle 7feed36dac more otp tests 2021-05-13 23:41:46 +02:00
antelle 6c7a824608 locale 2021-05-13 20:01:08 +02:00
antelle ed2c5af7e9 locale 2021-05-13 13:56:29 +02:00
antelle 0c143d0491 moved locales out of scripts 2021-05-13 13:05:57 +02:00
antelle 9efce05f11 eslint fix 2021-05-13 12:39:22 +02:00
antelle 4903b1e141 npm run eslint 2021-05-13 12:12:07 +02:00
antelle 5718f31fe6 otp 2021-05-13 12:11:18 +02:00
antelle 4fb25451a2 fix #1816: old Chromium support, such as Android Edge 2021-05-13 10:45:48 +02:00
antelle 860dd5bdcd file-saver 2021-05-13 10:13:17 +02:00
antelle 6326620cd8 kdbxweb tests 2021-05-13 10:09:50 +02:00
antelle c6c9c19be6 utils 2021-05-13 09:33:36 +02:00
antelle ac38b8f60a features 2021-05-13 09:15:59 +02:00
antelle 91e5a4c894 logger 2021-05-13 09:10:42 +02:00
antelle 385224077b more utils 2021-05-13 09:01:55 +02:00
antelle a011bf7ec2 Merge branch 'develop' into ts 2021-05-12 21:43:59 +02:00
antelle 58a6a97130 Merge branch 'master' into develop 2021-05-12 21:43:27 +02:00
antelle f59b846643 Merge branch 'release-1.18'
Build / linux (push) Canceled after 0s
Build / web (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
2021-05-12 21:40:25 +02:00
antelle 28d7dfeb67 bump version 2021-05-12 21:39:47 +02:00
antelle 6cc39d2107 fix #1808: restore KeeWeb from system tray on extension request 2021-05-12 21:38:54 +02:00
antelle a92a01095b fix #1814: option to disable auto-type title filter by default 2021-05-12 21:00:51 +02:00
antelle 3f4cddd2a2 fix #1811: app doesn't quit during update 2021-05-12 20:50:24 +02:00
antelle aa734ea976 fix #1813: fixed custom icon selection 2021-05-11 18:50:37 +02:00
antelle 71d9dd84ae password strength 2021-05-10 23:49:40 +02:00
antelle eaf5875d4c more utils 2021-05-10 23:41:54 +02:00
antelle caae1ac801 more utils 2021-05-10 23:21:18 +02:00
antelle 746d0196b3 protected-value 2021-05-10 23:10:36 +02:00
antelle f04f54cc82 fn.ts 2021-05-10 21:23:16 +02:00
antelle 30628004fd https link in the readme 2021-05-10 20:40:38 +02:00
antelle a6e87b52fd fix #1810: fixed the extension on old macOS starting 10.11 2021-05-10 20:40:30 +02:00
antelle 8132325e11 eslintrc formatting 2021-05-10 20:31:19 +02:00
antelle 57684537fa first test 2021-05-10 18:30:12 +02:00
antelle 167be95bd4 const 2021-05-10 18:21:56 +02:00
antelle 6cdf53f1a4 Merge branch 'develop' into ts 2021-05-10 18:12:36 +02:00
antelle 6d06d825e5 fixed donate button border 2021-05-10 18:12:11 +02:00
antelle c923e46321 sorted dependencies 2021-05-10 17:57:54 +02:00
antelle b122231485 tests 2021-05-10 17:56:09 +02:00
antelle 73f94402dd TS setup 2021-05-09 23:55:40 +02:00
antelle 0800d5f33a Merge branch 'master' into develop 2021-05-09 23:25:27 +02:00
antelle 337ef44b56 Merge branch 'release-1.18'
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
2021-05-09 14:32:23 +02:00
antelle 70b4effde8 fix #1806: fixed a possible config loading error during startup 2021-05-09 14:31:58 +02:00
antelle 9e4c0f5c47 Merge branch 'release-1.18' 2021-05-09 14:12:50 +02:00
antelle 535cdc72f7 fix #1805: auto-unchecking auto-type filters if nothing found 2021-05-09 14:07:22 +02:00
antelle 8d258ecab2 fix #1804: entry table sizing in Firefox 2021-05-09 10:17:55 +02:00
antelle 3079e28f6f bump version 2021-05-09 10:09:26 +02:00
antelle 4970290614 fix #1804: filling OTP in browser extensions 2021-05-09 10:08:59 +02:00
antelle 6929931cae Merge branch 'master' into develop 2021-05-09 09:04:12 +02:00
antelle e348310602 Merge branch 'release-1.18'
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
2021-05-08 22:33:52 +02:00
antelle 7abbd2f253 bump version 2021-05-08 22:32:53 +02:00
antelle c56698492e fix #1802: opening files with saved keyfiles 2021-05-08 22:32:35 +02:00
antelle bc4c33fcbb Merge branch 'release-1.18'
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
2021-05-08 21:02:32 +02:00
antelle 05d5ac960c bump version 2021-05-08 21:01:00 +02:00
antelle 80331401b5 Merge branch 'master' into release-1.18 2021-05-08 21:00:47 +02:00
antelle b4459e1247 fixed entry attachments display 2021-05-08 21:00:38 +02:00
antelle 706c82d3ca fixed Windows code signing
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
2021-05-08 19:57:02 +02:00
antelle 0e1b086096 Merge branch 'develop' 2021-05-08 19:37:01 +02:00
antelle 80359c98f5 bump version 2021-05-08 19:35:51 +02:00
antelle 034e0ec2e3 always write version with 2 spaces 2021-05-08 19:35:36 +02:00
antelle cc6839d13e fixed native messaging host mode 2021-05-08 17:48:30 +02:00
antelle 0ce436c2e9 fixed phonetic password generation 2021-05-08 17:13:10 +02:00
antelle 966d814281 fixed removing an extra url 2021-05-08 16:59:36 +02:00
antelle c983bc10ab fixed git tag name 2021-05-08 16:11:26 +02:00
antelle d603398da0 upgrading node.js on ci 2021-05-08 14:21:56 +02:00
antelle 1404d2688f ci bugfixes 2021-05-08 14:14:00 +02:00
antelle c72158cf0d release name 2021-05-08 14:12:05 +02:00
antelle 1e6ed1308f fix eslint 2021-05-08 13:50:25 +02:00
antelle fae241373a fixed tests 2021-05-08 13:46:08 +02:00
antelle 2bf4cd83df upgrading node.js 2021-05-08 13:45:14 +02:00
antelle efd3290ee8 upgraded github release publishing 2021-05-08 13:35:03 +02:00
antelle aa729d9af8 don't log extension events when not connected 2021-05-08 11:46:53 +02:00
antelle 2d6d3658a1 fixed an error during exit without launcher 2021-05-08 11:42:08 +02:00
antelle 0cbdd6281a kdbxweb v2 2021-05-08 11:38:23 +02:00
antelle a845a42d0d up deps 2021-05-08 10:56:49 +02:00
antelle 60329e086a translated application menu on macOS 2021-05-08 10:37:24 +02:00
antelle a3174b96d7 up languages 2021-05-08 09:57:33 +02:00
antelle 29c00066bc Safari extension link 2021-05-08 09:53:57 +02:00
antelle b90ffc4d3f fix #1794: update installation on Windows when minimize instead of close is enabled 2021-05-06 20:44:09 +02:00
antelle 7e030320f5 option to auto-save on file change, fix #1364 2021-05-06 20:13:58 +02:00
antelle c96bcad32d release notes formatting 2021-05-05 19:56:29 +02:00
antelle a655cce195 removed file version fix 2021-05-05 18:49:24 +02:00
antelle aafb0e7964 editorconfig 2021-05-04 17:18:26 +02:00
antelle 288f7f117f removed an http link 2021-05-02 20:51:32 +02:00
antelle 125ac2eda8 wording 2021-05-02 20:43:44 +02:00
antelle ea80bfae07 fix #keeweb/keeweb-connect#3: extension manifest file name 2021-05-01 19:20:14 +02:00
antelle 5e727a3547 fixed native messaging host permissions 2021-04-30 10:16:30 +02:00
antelle 6672b60d0f fix #1779: don't copy passwords from the inline genertor in fields 2021-04-29 14:20:36 +02:00
antelle 09fe1a4649 fix #1780: custom icon selection issue 2021-04-29 14:16:39 +02:00
antelle e4fa4cc413 fixed selecting password as custom field 2021-04-29 14:02:42 +02:00
antelle 0be60475cf selecting other fields for browser extensions 2021-04-29 12:55:00 +02:00
antelle b7e53185b0 returning otp codes 2021-04-29 12:16:53 +02:00
antelle cd8c76b3eb up deps 2021-04-29 11:30:01 +02:00
antelle a1d7a1fe48 ignoring errors during usb init 2021-04-29 10:15:41 +02:00
antelle c48153819f checking all urls in the auto-type search 2021-04-29 09:18:32 +02:00
antelle d2d5590887 replaced a constant 2021-04-29 08:31:37 +02:00
antelle 65b319e127 extension ids constants 2021-04-29 08:29:33 +02:00
antelle b34c0dd34e ignoring custom websites in the selectiong pop-up 2021-04-28 23:47:56 +02:00
antelle ddc1a371bf increased the timeout 2021-04-28 23:40:37 +02:00
antelle a0c0b7b195 cancel button in the entry selection view 2021-04-28 23:37:15 +02:00
antelle b07cea9049 option to show an empty entry selection screen 2021-04-28 23:29:13 +02:00
antelle 991388d4cd removed debugging code 2021-04-28 23:09:24 +02:00
antelle 7adc77c823 closing the selection view on inactivity 2021-04-28 23:08:01 +02:00
antelle 550f93d4ae release notes
fix #874
2021-04-28 22:12:07 +02:00
antelle b43187e5b8 update deps again 2021-04-28 21:08:42 +02:00
antelle 6230710bb0 fixing build 2021-04-28 21:07:22 +02:00
antelle ff119cbc0a Revert "audit fix"
This reverts commit 2a2ec713
2021-04-28 21:05:22 +02:00
antelle 2a2ec713af audit fix 2021-04-28 21:04:37 +02:00
antelle 41eb560d1a fixed deps 2021-04-28 21:03:49 +02:00
antelle f7b9b91144 temporary safari link 2021-04-28 20:25:46 +02:00
antelle 97ab5d066e Added extension links 2021-04-28 20:22:21 +02:00
antelle 448e19d28c fixed entry searching with subdomains 2021-04-28 18:57:41 +02:00
antelle 391f2c9c00 fixed entry creation 2021-04-28 18:29:45 +02:00
antelle 18524ad9eb returning one matching entry automatically 2021-04-28 17:59:47 +02:00
antelle 732c35625b entry selection filters 2021-04-28 17:34:48 +02:00
antelle 95857450c2 focusing KeeWeb before entry selection 2021-04-28 12:04:54 +02:00
antelle 98ea7a542d extracted select-entry-filter 2021-04-28 11:29:48 +02:00
antelle 338f6d47d1 extracted entry selection view 2021-04-28 09:44:02 +02:00
antelle fdb492c572 don't prevent closing main window during auto-type 2021-04-28 08:25:18 +02:00
antelle ce3ff8c3d8 fixed extra file opened during auto-type 2021-04-28 08:23:15 +02:00
antelle 1789d9bb67 up deps 2021-04-28 07:47:13 +02:00
antelle 1883b527a4 fixed window blur during auto-type 2021-04-27 21:38:31 +02:00
antelle 2f4a9d450a displaying extension name in views 2021-04-27 20:01:53 +02:00
antelle 12fc33a15e fixed web extension focus 2021-04-27 19:38:27 +02:00
antelle e4693ecf61 updating entries 2021-04-27 19:15:03 +02:00
antelle c15d709db2 fixed table view column width 2021-04-27 16:23:49 +02:00
antelle e09040b0fb fixed auto-type from minimized state 2021-04-27 14:49:13 +02:00
antelle 4477c3fc2c get-logins messages 2021-04-27 14:29:00 +02:00
antelle f52a00a156 implemented set-login for extensions 2021-04-27 13:58:43 +02:00
antelle 946a063993 fixed data decryption error 2021-04-26 23:55:44 +02:00
antelle d3fcbcb6a5 fixed read passwords count display 2021-04-26 23:44:41 +02:00
antelle f91cfc0f79 processing triggerUnlock sent by the extension 2021-04-26 22:35:17 +02:00
antelle f0bbc54fd5 fixed extension version 2021-04-26 22:29:02 +02:00
antelle 3ca5f94b9b creating new groups form browser extensions 2021-04-26 20:47:43 +02:00
antelle 7a35ebec73 fixed a memory leak
see #1580
2021-04-26 19:20:29 +02:00
antelle 66d3623f90 implemented new group creation 2021-04-26 16:40:36 +02:00
antelle 8c9badd440 checking available files per connection 2021-04-26 15:36:21 +02:00
antelle e0d47a474d switching to the open view on request 2021-04-26 13:40:37 +02:00
antelle 1a8aff0594 fix eslint 2021-04-26 13:34:33 +02:00
antelle cf5e01c213 wording 2021-04-26 13:31:57 +02:00
antelle ffae956e21 removing empty websites 2021-04-26 13:30:12 +02:00
antelle 5c4cb7ff6d displaying extra websites as urls 2021-04-26 13:26:27 +02:00
antelle 7794c8b89b release notes 2021-04-26 12:49:59 +02:00
antelle bb78e8e8a7 adding multiple websites to entries 2021-04-26 12:49:25 +02:00
antelle 00a2a95adc fixed read passwords display 2021-04-26 12:22:35 +02:00
antelle e55dd47f6e don't hide keeweb after successful result 2021-04-26 12:16:22 +02:00
antelle 7b10bda0a4 eslint fix 2021-04-26 12:08:30 +02:00
antelle d5b9aefa01 unlocking on request from browser extension 2021-04-26 12:06:03 +02:00
antelle cdc3f5e1df displaying a message on the open screen 2021-04-26 11:51:24 +02:00
antelle 8fc6f49fb4 reworked unlocking files for auto-type and browser extension connection
fix #1768
2021-04-26 11:20:20 +02:00
antelle 29e5c14009 setting for saving credentials 2021-04-25 23:17:14 +02:00
antelle fe9ff205b9 wording 2021-04-25 23:02:02 +02:00
antelle 87b59eccee fixed extension connection on web 2021-04-25 20:38:49 +02:00
antelle 42cb5a6c36 editing file permissions in settings 2021-04-25 19:59:52 +02:00
antelle 9826965803 session management in settings 2021-04-25 18:08:16 +02:00
antelle 47153e41d3 extension connection timeout 2021-04-25 14:09:54 +02:00
antelle 677b428e63 all other files and all files 2021-04-25 13:50:03 +02:00
antelle 15936fcef0 extension connection dialog 2021-04-25 13:46:59 +02:00
antelle b2e828e7ef up native messaging host 2021-04-25 00:17:35 +02:00
antelle ac6e5a3ae8 fixed processing first message 2021-04-24 23:47:35 +02:00
antelle 3722477eea added a warning about extension association 2021-04-24 19:31:39 +02:00
antelle 72d0f76acc getting parent info for cmd 2021-04-24 10:48:28 +02:00
antelle b7333574aa replaced .exe in app name on windows 2021-04-24 10:38:43 +02:00
antelle 5caccbd1f5 getting appName 2021-04-24 10:26:07 +02:00
antelle 698b559935 up native-messaging-host 2021-04-24 10:06:55 +02:00
antelle 36d5e8f730 windows process information 2021-04-23 23:49:14 +02:00
antelle 233721bf51 extension installation on Windows 2021-04-23 23:17:35 +02:00
antelle 822602a38f added a note about windows-registry 2021-04-23 21:25:49 +02:00
antelle e69dbf697c up keeweb-native-modules 2021-04-23 21:17:11 +02:00
antelle 184d71a1b9 fixed firefox manifest 2021-04-21 23:30:32 +02:00
antelle ccb9b03287 creating native manifests 2021-04-21 22:23:17 +02:00
antelle dd4ad6d72b starting the extension host based on settings 2021-04-21 20:27:55 +02:00
antelle 195e2cc8f0 fixed exports 2021-04-21 20:09:26 +02:00
antelle ef573336d8 moved isDev to utils 2021-04-21 19:31:37 +02:00
antelle 9377a849f6 added native messaging host package 2021-04-21 19:28:44 +02:00
antelle 00ccbf4be2 deleted native-messaging-host 2021-04-20 17:07:50 +02:00
antelle 00159d26dc extracted protocolimpl 2021-04-19 23:40:57 +02:00
antelle b4f93adf05 reorganized imports a bit 2021-04-19 23:33:16 +02:00
antelle 5bbc9003f4 enable extension settings 2021-04-19 22:40:59 +02:00
antelle c4be926b7c better extension messages 2021-04-19 21:56:08 +02:00
antelle 147e3911f1 fixed no extensions message 2021-04-19 21:31:55 +02:00
antelle c7b814fc01 browser extension settings 2021-04-19 21:29:52 +02:00
antelle 8525571afc disabled the extension setting for mobile 2021-04-19 18:18:37 +02:00
antelle 5c5de91672 fixed links in desktop apps 2021-04-19 18:15:41 +02:00
antelle 7dbb0a2e8f added a missing whitespace 2021-04-18 21:42:22 +02:00
antelle 11b54ffdf9 wording 2021-04-18 21:39:24 +02:00
antelle 5d76ac33dd wording 2021-04-18 21:38:58 +02:00
antelle 8e92bf3766 kw.runtimeData api 2021-04-18 21:37:17 +02:00
antelle 56517eec62 typo 2021-04-18 21:35:45 +02:00
antelle ed56f0733e added an option to focus KeeWeb when the file is locked 2021-04-18 21:02:43 +02:00
antelle 3fd799ee74 browser extension settings page 2021-04-18 20:55:27 +02:00
antelle 4ed8a67eda simplified a condition 2021-04-18 18:57:38 +02:00
antelle cbb9a8dbd0 sending origin information in the first message 2021-04-18 18:50:03 +02:00
antelle 4280b84459 moved browser socket connection management to the main process 2021-04-18 14:26:45 +02:00
antelle e06e9ac1f8 moved ipc handlers setup to corresponding files 2021-04-18 11:50:11 +02:00
antelle 7bea4ad282 added team id to avoid the requirement for codesigning config 2021-04-17 20:33:37 +02:00
antelle 316c14d845 shorter socket name 2021-04-17 17:25:14 +02:00
antelle d17be63312 keeweb-browse => keeweb-connect 2021-04-17 17:00:14 +02:00
antelle 2c2253db31 renamed the extension 2021-04-17 16:57:06 +02:00
antelle a3128e56a3 client.supportsNotifications 2021-04-17 09:51:18 +02:00
antelle de0cf0ce67 fixed an empty notification about closing files 2021-04-17 09:28:25 +02:00
antelle e3f33b9d4c don't require client id for ping 2021-04-16 21:06:20 +02:00
antelle 27143e2663 fixed macos socket 2021-04-15 23:46:34 +02:00
antelle 566e2fb35d creating browser socket in a group container on macOS 2021-04-15 20:38:13 +02:00
antelle dc5ada1c04 etter error handling 2021-04-14 21:31:29 +02:00
antelle 603e698f5a fixed socket cleanup on windows 2021-04-14 21:26:58 +02:00
antelle f893dcb19a native messaging host tests 2021-04-14 21:11:24 +02:00
antelle 27b116798e tests fix 2021-04-14 20:41:45 +02:00
antelle ae932e5710 windows extension connection fixes 2021-04-14 20:34:03 +02:00
antelle bab5a979be windows compilation options 2021-04-13 23:37:43 +02:00
antelle 1b8c9a3e0c fixed linux helper paths 2021-04-13 23:03:38 +02:00
antelle 99d0fa30ed removed keeweb launching 2021-04-13 22:59:39 +02:00
antelle 5cc146481b fixed grunt-cmake 2021-04-13 22:55:38 +02:00
antelle 102da5cba1 signing the native messaging host 2021-04-13 22:40:35 +02:00
antelle d374eecb18 running cmake on build 2021-04-13 22:39:07 +02:00
antelle 08d31c0ffe don't launch keeweb if it's not running 2021-04-13 21:37:00 +02:00
antelle c62e40465a eslint 2021-04-13 20:43:34 +02:00
antelle 5367f32d5c reorganized app startup 2021-04-13 20:27:20 +02:00
antelle ad20698a42 deleted the browser extension setting 2021-04-13 20:27:07 +02:00
antelle e865d80a63 moved more code to protocol-impl 2021-04-12 23:42:42 +02:00
antelle 81a311e7fa refactored browser extension connector module 2021-04-12 23:37:08 +02:00
antelle 5397fa8fd3 create-group 2021-04-12 23:23:22 +02:00
antelle b9e08cd9e3 implemented get-database-groups 2021-04-12 23:05:57 +02:00
antelle fe86cd6320 native messaging on Firefox 2021-04-11 23:28:24 +02:00
antelle bba07bb83a fixed constant name 2021-04-11 19:52:49 +02:00
antelle 83a53ee1f0 error code property 2021-04-11 19:14:34 +02:00
antelle 23ba363a0d asking questions about accessing data in the extension 2021-04-11 18:59:33 +02:00
antelle 101aee81c0 added more browser extensions to the native host 2021-04-11 18:01:36 +02:00
antelle fa60d02129 option to debug browser extension transport 2021-04-11 17:59:05 +02:00
antelle 6a9e5fd801 always returning KeeWeb hash 2021-04-11 17:22:58 +02:00
antelle 12ae7845ec renamed the file 2021-04-11 15:41:39 +02:00
antelle 045e8ee96f fixed error codes 2021-04-11 15:04:04 +02:00
antelle 993f75b14e fixed some contract types 2021-04-11 14:53:56 +02:00
antelle b48f3746bc closing browser extension connections 2021-04-11 12:48:58 +02:00
antelle dcc477acbc tightened content security policy to prevent browser extension from adding scripts to KeeWeb 2021-04-11 11:44:51 +02:00
antelle 5f4f007b31 more extension logging 2021-04-11 10:17:02 +02:00
antelle 9d4788cb7c returning appName only for own extension 2021-04-10 23:37:24 +02:00
antelle 5a1380f9ef removed extra check 2021-04-10 23:36:21 +02:00
antelle 0d82aa26f3 checking own extension 2021-04-10 23:35:42 +02:00
antelle 05f2ec19f2 reorganized the extension connector code 2021-04-10 21:32:29 +02:00
antelle 25c3c9c565 connecting to the native app from the extension 2021-04-10 21:16:48 +02:00
antelle d6e7e3d4a0 reverted the timeout 2021-04-10 19:33:31 +02:00
antelle 6148112904 max 1 minute to connect to KeeWeb 2021-04-10 19:31:34 +02:00
antelle ba338e9282 launching keeweb 2021-04-10 19:29:24 +02:00
antelle 2e132690d1 fixed deletion 2021-04-10 18:59:58 +02:00
antelle 8f1b6ca3b7 removed some manual memory management 2021-04-10 18:54:15 +02:00
antelle 85d0252972 removed double stderr 2021-04-10 18:47:00 +02:00
antelle 077f72a0c5 printing stderr 2021-04-10 18:42:12 +02:00
antelle 25bec513f3 extracted some constants 2021-04-10 18:39:23 +02:00
antelle 0a6378d84c renamed the tests 2021-04-10 18:39:12 +02:00
antelle 1e6034ce37 native host tests 2021-04-10 18:38:27 +02:00
antelle ef6e5ebcbe added native messaging host 2021-04-10 17:00:10 +02:00
antelle 19a42b7463 fix #1783: crash after disabling USB devices on Linux 2021-04-10 00:19:58 +02:00
antelle 9d0e608454 Merge branch 'master' into develop
# Conflicts:
#	app/scripts/locales/base.json
#	app/scripts/storage/impl/storage-gdrive.js
#	package-lock.json
#	release-notes.md
2021-04-09 20:10:52 +02:00
antelle bd9a98dbfd fixed docker image tagging 2021-04-09 20:09:44 +02:00
antelle 0ffca3dfe4 npm audit fix 2021-04-09 19:03:02 +02:00
antelle 01958559ee fix #1767: updater issues on macOS 2021-04-09 19:01:55 +02:00
antelle bb4aef206a fixed wait-pid 2021-04-09 19:01:54 +02:00
antelle e74227b0db added --verbose option to the installer 2021-04-09 19:01:53 +02:00
antelle a47aec1cc4 bump version 2021-04-09 19:01:52 +02:00
antelle cd9d8cde3e release notes 2021-04-09 19:01:49 +02:00
antelle d4f68d5ec7 fix #1786: refresh_token in Google Drive 2021-04-09 19:01:48 +02:00
antelle a910cfcb35 fix #618: team drive support in Google Drive 2021-04-09 19:01:47 +02:00
antelle 962de503fd up kdbxweb 2021-04-09 19:01:27 +02:00
antelle f40e72c882 shared drives variable 2021-04-09 18:20:15 +02:00
antelle b7993e1d0e renamed team drives to shared drives 2021-04-09 18:19:26 +02:00
antelle d6e5e73e82 fixed refresh_token in Google Drive
see #1786
2021-04-08 23:07:19 +02:00
antelle 1794f87f99 fix #618: team drive support in Google Drive 2021-04-08 21:47:57 +02:00
antelle 81c7d57f30 localized templates folder name 2021-04-08 20:09:25 +02:00
antelle b4f0149bd8 saving extension name 2021-04-08 19:01:08 +02:00
antelle 87ec06eef0 browser extension: generate-password method 2021-04-08 18:10:48 +02:00
antelle c764548214 browser extension: generate-password method 2021-04-08 17:59:39 +02:00
antelle c78af7c3ad setting nonce in response payload 2021-04-08 17:36:42 +02:00
antelle f9cd0d4e29 browser extension: asking for user attention 2021-04-08 17:28:41 +02:00
antelle ee03435ca7 implemented lock-database 2021-04-07 22:49:23 +02:00
antelle a9b83256c6 returning only active db hashes 2021-04-07 22:07:16 +02:00
antelle 7086ddcf58 returning the list of hashes 2021-04-07 22:04:21 +02:00
antelle 26d226bb17 browser-extension: returning appName 2021-04-07 21:16:48 +02:00
antelle dc4742bf5c browser extension connector: implemented get-databasehash 2021-04-07 21:08:22 +02:00
antelle 933df5fae4 browser extension file notifications 2021-04-06 21:27:58 +02:00
antelle 4b17ac19dc browser extension backend 101 2021-04-06 20:10:42 +02:00
antelle 43f6a4f499 clone keeweb-browser in dev-env 2021-04-05 09:53:49 +02:00
antelle 076b99676d fix #1775: special error message for cases when Touch ID is changed after setup
also added Touch ID key deletion when it's disabled
2021-04-02 18:47:04 +02:00
antelle b3dfa05a4a added menu translations 2021-04-02 13:34:27 +02:00
antelle c5946b1a0b fixed default character count calculation in the generator 2021-04-01 21:57:42 +02:00
antelle 58a85eabdf fix #1774: password generator now includes all selected character ranges 2021-04-01 21:54:42 +02:00
Dimitri Witkowski 8a1d9b96dd Merge pull request #1770 from aslafy-z/patch-1
fix(docker): publish all docker image tags
2021-03-29 20:31:41 +02:00
Zadkiel 36a3d2f766 fix(docker): publish all docker image tags 2021-03-29 20:25:37 +02:00
antelle 68010076f9 renamed external model to otp-device 2021-03-28 19:05:20 +02:00
antelle 92da783e82 moved spawn to the main process 2021-03-28 18:41:31 +02:00
antelle 7d1e343d25 fixed wait-pid 2021-03-27 14:24:54 +01:00
antelle 84d17b7255 added --verbose option to the installer 2021-03-27 14:11:28 +01:00
antelle 64e06a32ec Merge branch 'master' into develop
# Conflicts:
#	package-lock.json
#	release-notes.md
2021-03-27 10:25:29 +01:00
antelle 4ee87e197d using new accounts ykman command
Build / publish (push) Canceled after 0s
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
2021-03-27 09:19:20 +01:00
antelle cace667b26 release notes 2021-03-27 09:19:19 +01:00
antelle 67d3e28af7 bump version 2021-03-27 09:19:18 +01:00
antelle 3c5f4e7b84 release notes 2021-03-27 09:19:17 +01:00
antelle 8f913c737c removed debugging code from build 2021-03-27 09:19:16 +01:00
antelle 8ba147f52f fix #1762: line breaks in Markdown notes 2021-03-27 09:19:15 +01:00
antelle 9cfbd24b76 fix #1758: export format HTML issues 2021-03-27 09:19:14 +01:00
antelle 259abf6d25 added missing overflow to revealed passwords 2021-03-27 09:19:13 +01:00
antelle 8c59838a6f fix #1734: overlapping generator icon on password inputs 2021-03-27 09:19:12 +01:00
antelle f7d24c6379 fix #1725: setting expire date in the past 2021-03-27 09:19:11 +01:00
antelle 0f5466e075 fix #1755: calendar tooltips in different time zones 2021-03-27 09:19:10 +01:00
antelle 7ab0e83f55 ykman v4 support 2021-03-27 09:19:09 +01:00
antelle dc02ede8d7 up kdbxweb 2021-03-27 09:19:08 +01:00
antelle 42e484827f restored the missing disk icon 2021-03-27 09:19:07 +01:00
antelle 576c8f97bd removed dist from dev-env 2021-03-27 09:19:06 +01:00
antelle 808b4a687d fix #1762: line breaks in Markdown notes 2021-03-24 17:02:05 +01:00
antelle 954f2c235b fix #1758: export format HTML issues 2021-03-22 17:13:09 +01:00
antelle 51a7bbbfb8 added missing overflow to revealed passwords 2021-03-21 17:38:36 +01:00
antelle 9b5f5857bb fix #1734: overlapping generator icon on password inputs 2021-03-21 17:35:06 +01:00
antelle e66f52a8ce fix #1753: option to use short-lived tokens in cloud storages 2021-03-21 17:22:38 +01:00
antelle 8023bcea96 fix #1725: setting expire date in the past 2021-03-21 16:38:09 +01:00
antelle dfb7491503 fix #1755: calendar tooltips in different time zones 2021-03-21 16:36:18 +01:00
antelle b43d9c963a ykman v4 support 2021-03-20 22:45:42 +01:00
antelle 51c0637134 fixed list item size in firefox 2021-03-20 22:40:13 +01:00
antelle b16c23190b fixed scrolled entry modification 2021-03-20 20:26:29 +01:00
antelle fddf2892cd fix #1580: high memory usage on large files, virtual scrolling of entries 2021-03-20 19:17:57 +01:00
antelle 53b5715da0 up kdbxweb 2021-03-19 23:07:10 +01:00
antelle 3a79fcb366 optimized memory consumption for large files
see #1580
2021-03-19 22:52:41 +01:00
antelle 4df034ac55 restored the missing disk icon 2021-03-19 22:11:55 +01:00
antelle a0bb04fe3a removed dist from dev-env 2021-03-19 22:08:33 +01:00
antelle a923f28a8d Merge branch 'master' into develop
# Conflicts:
#	release-notes.md
2021-03-19 18:57:01 +01:00
antelle 78642f1c9b opening XML and CSV files using the Open button 2021-03-19 18:56:36 +01:00
antelle f8a85af859 Merge branch 'release-1.17' into master
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
2021-03-18 17:14:58 +01:00
antelle bdb5bd0428 bump version 2021-03-18 17:14:37 +01:00
antelle 9e07f55c12 fix #1749: auto-type freezes on macOS 2021-03-18 17:14:01 +01:00
antelle 6a3e129ed5 fixed update installation when minimize on close is enabled
see #1740
2021-03-15 19:31:40 +01:00
antelle 879ba17760 Merge branch 'master' into develop
# Conflicts:
#	release-notes.md
2021-03-14 21:17:26 +01:00
antelle 0d2107e72a Merge branch 'release-1.17' into master
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
2021-03-14 20:24:38 +01:00
antelle a23a47fded bump version 2021-03-14 20:23:03 +01:00
antelle 7737a29cca fix #1747: white screen in old Safari 2021-03-14 20:22:37 +01:00
antelle 34278b3bff fixed usb-detection link 2021-03-13 19:37:47 +01:00
antelle 40b0643eaa Merge branch 'master' into develop 2021-03-13 19:31:54 +01:00
antelle ae7f5fbff2 Merge branch 'release-1.17' into master
Build / publish (push) Canceled after 0s
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
2021-03-13 17:46:55 +01:00
antelle 0a776c6a72 Merge branch 'release-1.17' into develop
# Conflicts:
#	release-notes.md
2021-03-13 17:31:05 +01:00
antelle 5caecb1c8f fix #1738: fixed auto-type on Linux with NumLock pressed 2021-03-13 14:27:48 +01:00
antelle 0def3f8b2d fix #1745: deleting selected text in auto-type selector 2021-03-13 10:11:32 +01:00
antelle 1593acd8e9 fixed auto-type searchbox clear button alignment 2021-03-13 10:01:51 +01:00
antelle da5553364a using proper call sequence in node-usb-detection 2021-03-12 23:37:29 +01:00
antelle b7c03490d8 bump version 2021-03-12 23:17:22 +01:00
antelle b8dd7b0f71 fix #1744, fix #1743: fixed crashes in the USB module on Windows 2021-03-12 23:06:19 +01:00
antelle e7a8d5232f Merge branch 'master' into develop
# Conflicts:
#	release-notes.md
2021-03-10 21:37:23 +01:00
antelle c638fa38e8 Merge branch 'release-1.17' into master
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
2021-03-10 19:07:57 +01:00
antelle f74b054f01 release date 2021-03-10 19:06:56 +01:00
antelle b7af33edae bump version 2021-03-10 19:01:00 +01:00
antelle 166211b6f8 fix #1735: issue with auto-typing some characters on Windows 2021-03-10 17:58:17 +01:00
antelle f8ec47bfdb release notes 2021-03-08 22:34:29 +01:00
antelle 4e84121553 cleaned up legacy auto-type 2021-03-08 22:29:59 +01:00
antelle ccf4ce8e58 package name 2021-03-07 16:25:07 +01:00
antelle 6ba3d44fa1 Merge branch 'master' into develop 2021-03-07 15:16:48 +01:00
antelle c03ed76fec increased memory limit
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
2021-03-07 14:35:27 +01:00
antelle 31214b10e7 Merge branch 'develop' into master 2021-03-07 14:23:29 +01:00
antelle 5bbc324b2e bump version 2021-03-07 14:22:49 +01:00
antelle 7dcb22950e fixed bump version 2021-03-07 14:22:41 +01:00
antelle 3c06f1f1a3 release date 2021-03-07 14:20:32 +01:00
antelle 6bcf5161b1 release notes 2021-03-07 11:14:34 +01:00
antelle ccc6765e2e release date 2021-03-07 10:56:18 +01:00
antelle 14d40d4e2d release notes 2021-03-07 10:55:41 +01:00
antelle 75d563b320 removed debugging code 2021-03-06 21:40:23 +01:00
antelle 2fdd53b55e removed debugging code 2021-03-06 21:30:51 +01:00
antelle 4ac16a6701 debugging patching on ci 2021-03-06 21:24:45 +01:00
antelle e998788d25 git+https 2021-03-06 21:05:54 +01:00
antelle e23b80b11b languages 2021-03-06 20:52:59 +01:00
antelle 7eb884dcb9 up deps 2021-03-06 20:17:47 +01:00
antelle 92397adbb3 eslint 2021-03-06 20:17:31 +01:00
antelle 828485789f ignore password quality warnings alert box 2021-03-06 19:19:23 +01:00
antelle 2f84474216 disabled draggable window on Windows 2021-03-06 11:38:05 +01:00
antelle 762aab397d fixes for custom titlebar 2021-03-06 11:35:14 +01:00
antelle b03cb4590f release notes 2021-03-05 22:12:09 +01:00
antelle 5d40831dd7 reverted debug code 2021-03-05 21:16:42 +01:00
antelle 0d291afb05 fix #1729: prevent double encoding move path 2021-03-05 21:16:12 +01:00
antelle e107c5c108 disabled auto-switching theme 2021-03-05 21:08:09 +01:00
antelle 44905e674d fixed titlebar events 2021-03-03 23:46:23 +01:00
antelle 5b790e711a added a logo on the custom titlebar for Windows 2021-03-03 23:42:41 +01:00
antelle 1a9c54b237 extracted the inline logo 2021-03-03 22:33:29 +01:00
antelle 0f4434a361 fix #689: custom title bar on Windows 2021-03-03 22:12:49 +01:00
antelle 7e2823903b up electron 2021-03-03 17:34:57 +01:00
antelle 92937dbb86 fix #1727: tabs in notes 2021-03-03 17:13:41 +01:00
antelle 0868efe095 added --native-module-host-process option 2021-03-02 21:17:04 +01:00
antelle 97374f63f9 Merge branch 'master' into develop
# Conflicts:
#	desktop/package-lock.json
#	package-lock.json
#	release-notes.md
2021-03-02 20:10:18 +01:00
antelle 69f7b02ce6 Merge branch 'release-1.16' into master
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
2021-03-02 19:21:21 +01:00
antelle b5ee682a41 bump version 2021-03-02 19:18:46 +01:00
antelle 70f82bdfd8 release date fix 2021-03-02 19:18:29 +01:00
antelle e70185560b release notes 2021-03-02 19:18:21 +01:00
antelle be4be0e7e8 fix #1715: storage authentication in Epiphany browser 2021-03-02 19:17:42 +01:00
antelle b9a5c64113 fix #1713: OneDrive authentication on web 2021-03-02 19:17:36 +01:00
antelle 215f398547 fix #1726: search in protected fields 2021-03-02 19:17:29 +01:00
antelle ace18f9d95 fix #1715: storage authentication in Epiphany browser 2021-03-01 18:06:45 +01:00
antelle c4ec91f61a fix #1713: OneDrive authentication on web 2021-03-01 18:03:13 +01:00
antelle a4881419df fix #1726: search in protected fields 2021-03-01 17:55:08 +01:00
antelle 839359a794 removed a readme 2021-03-01 17:53:20 +01:00
antelle d4d9b7c7a7 readme about translations 2021-02-26 18:54:43 +01:00
antelle d4526c0c8a release notes 2021-02-26 18:48:18 +01:00
Dimitri Witkowski 78f0bc6f02 Merge pull request #1721 from enter-is/develop
Option to minimize KeeWeb on copy
2021-02-26 18:46:43 +01:00
is ad3f5afeba Option to minimize KeeWeb on copy
Code review changes: https://github.com/keeweb/keeweb/pull/1721

https://github.com/keeweb/keeweb/issues/1718
2021-02-23 08:43:01 +02:00
is 7c4326939a Option to minimize KeeWeb on copy
https://github.com/keeweb/keeweb/issues/1718
2021-02-22 15:02:42 +02:00
antelle e5428b67b8 npm 2021-02-14 11:42:10 +01:00
antelle 59616bd8af disabled touch id check 2021-02-14 11:36:20 +01:00
antelle fdc9ac95d2 up native-modules 2021-02-13 21:06:14 +01:00
antelle a8f0d1af62 extended the oauth fix to iOS, see #1711 2021-02-12 20:14:21 +01:00
antelle f6e377f222 fix #1711: workaround for Dropbox on iOS PWA 2021-02-12 20:14:07 +01:00
antelle c43d7ab92a extended the oauth fix to iOS, see #1711 2021-02-12 09:34:42 +01:00
antelle 0464e1de5c fix #1711: workaround for Dropbox on iOS PWA 2021-02-11 23:01:28 +01:00
antelle 7a7381eac0 don't spawn another process 2021-02-09 21:38:49 +01:00
antelle 1379db1e92 fixed yubikey touch 2021-02-09 21:37:54 +01:00
antelle ee10894f5f added an option to prevent another process from being created 2021-02-09 20:19:12 +01:00
antelle 87d760708d removed an extra code 2021-02-09 19:54:30 +01:00
antelle ec7155809b fixed native module helper 2021-02-08 22:49:53 +01:00
antelle 5af7837468 patching electron 2021-02-06 14:46:24 +01:00
antelle d3f79af2ab up 2021-02-06 14:25:12 +01:00
antelle a6c0fc3984 option do disable caching files in offline storage
fix #404, fix #1115
2021-02-06 13:53:12 +01:00
antelle 56604de7f1 up deps 2021-02-06 13:24:59 +01:00
antelle d5e6199775 added linux dependencies 2021-02-04 21:30:52 +01:00
antelle 15920abcf7 replaced a year 2021-02-04 21:09:21 +01:00
antelle 88205d716a new npm 2021-02-04 21:05:26 +01:00
antelle fa1a16f140 added an explanation about auto-type issues on macOS 2021-02-04 20:54:13 +01:00
antelle 4f8075ca6c package-lock 2021-02-04 19:47:15 +01:00
antelle 2615d0644d up 2021-02-03 23:59:15 +01:00
antelle d2686937fd fixed linux build 2021-02-03 22:00:03 +01:00
antelle b60307e28b removed com.apple.security.get-task-allow entitlement 2021-02-03 21:58:49 +01:00
antelle 08d49ddc54 fix #679, fix #1383: Touch ID on macOS 2021-02-03 20:30:59 +01:00
antelle 4cdc80e530 Touch ID settings, see #679 2021-02-01 22:24:53 +01:00
antelle acd360efb9 cleaned up old touch id implementation 2021-02-01 21:08:02 +01:00
antelle 87ad89beeb fix #1697: creating files with Argon2id KDF 2021-02-01 17:25:46 +01:00
antelle c2663ca7d8 new completion page after storage provider authentication 2021-01-31 13:24:49 +01:00
antelle 4e58285cc2 using batch text entry 2021-01-31 12:27:20 +01:00
antelle ef354fb8af up deps 2021-01-31 00:47:27 +01:00
antelle 79ce535d4a up deps 2021-01-31 00:20:34 +01:00
antelle 50c43c4408 year 2021-01-30 23:41:32 +01:00
antelle 8fdec5aadc added a module link 2021-01-30 21:40:00 +01:00
antelle 73eccd5308 added a message about delay 2021-01-30 21:37:09 +01:00
antelle 4449677e36 entering text as key codes 2021-01-30 21:34:08 +01:00
antelle 8dc3a4b51f fixed vkey 2021-01-30 20:29:26 +01:00
antelle cd2de3a1db native auto type: unpressing keys 2021-01-30 20:22:13 +01:00
antelle 1fa0eebc3b changed ipc method naming convention 2021-01-30 18:39:25 +01:00
antelle e13002bab3 typing key codes 2021-01-30 18:24:42 +01:00
antelle a750e80ea1 auto-type progress 2021-01-30 16:00:57 +01:00
antelle 66e1b0a089 first auto-type emitter implementation 2021-01-30 15:37:25 +01:00
antelle 00c0b3f88c native auto-type helper implementation 2021-01-30 14:55:00 +01:00
antelle 674311cb4b native auto-type methods 2021-01-30 14:16:32 +01:00
antelle f54b8e00e1 up deps 2021-01-30 14:03:59 +01:00
antelle c1beac5d0d up native-modules 2021-01-30 13:18:11 +01:00
antelle 7123345341 cleaned up useless conditions 2021-01-28 08:08:11 +01:00
antelle 0e2475e667 cleanup 2021-01-17 08:20:08 +01:00
antelle acf1f1146d removed other links 2021-01-17 08:14:42 +01:00
antelle d136fa4fdf disabled discussions 2021-01-17 08:14:01 +01:00
antelle 61067391b6 added a link to node-secure-enclave 2021-01-10 17:23:23 +01:00
antelle affebb1ba4 progress logging 2021-01-10 17:16:21 +01:00
antelle cbffa3d4ef message formatting 2021-01-10 17:11:47 +01:00
antelle 6ef5ae2517 separated encrypt and decrypt 2021-01-10 16:56:53 +01:00
antelle 9701496897 better message 2021-01-10 16:40:16 +01:00
antelle 22d6a3011f added a string for touch id 2021-01-10 16:31:50 +01:00
antelle d22ddd99f6 secure enclave support for #679 2021-01-10 14:31:33 +01:00
antelle 4e8648fca0 using the provisioning profile on ci 2021-01-10 12:23:18 +01:00
antelle 9f49c357e9 using provisioning profile for codesigning macos apps 2021-01-10 12:16:27 +01:00
antelle d318467039 added a possibility to build a signed desktop app with npm dev-desktop-macos-signed 2021-01-10 11:55:00 +01:00
antelle b05c25ac1a up keeweb-native-modules 2021-01-10 11:36:51 +01:00
antelle 5dd0d51514 removed endswith 2021-01-10 09:59:51 +01:00
antelle c7574a6b83 debug message in the installer 2021-01-10 09:41:30 +01:00
antelle ab64e9343b sleep time 2021-01-10 09:36:34 +01:00
antelle b82cb0e849 fixed Windows update installation 2021-01-10 09:28:09 +01:00
antelle c44a8fab42 fixed update buttons margin 2021-01-10 09:25:12 +01:00
antelle 9a75eb0a22 removed a newline 2021-01-10 00:17:14 +01:00
antelle f994278a8b windows update installer spaces fix 2021-01-10 00:16:45 +01:00
antelle bd882d0e17 fixed windows update installer 2021-01-10 00:14:28 +01:00
antelle fddf62409a fixed updater settings view 2021-01-09 23:04:22 +01:00
antelle a8967ac764 timeout before copying files in the updater 2021-01-09 22:10:39 +01:00
antelle 20bc254a42 fixed windows uninstaller 2021-01-09 21:52:38 +01:00
antelle e298d5fbd8 ignoring cancellation errors 2021-01-09 21:37:20 +01:00
antelle ff54c2070d fixed the macos updater 2021-01-09 21:34:59 +01:00
antelle e092caa2ef better syntax 2021-01-09 18:48:48 +01:00
antelle feb44be9d0 disable updater on Linux 2021-01-09 18:00:19 +01:00
antelle a43a2e8ce2 checking minVersion against app version 2021-01-09 17:53:13 +01:00
antelle 6fcf77829d using ES5 in the installer 2021-01-09 17:41:34 +01:00
antelle 733833e8a4 fix #1661: using the new Windows installer 2021-01-09 17:15:50 +01:00
antelle 890f998fe0 updating support in win32 installer 2021-01-09 17:14:56 +01:00
antelle 28c708f599 moved desktop scripts 2021-01-09 13:30:19 +01:00
antelle f1e536cbcf moved icons to a folder 2021-01-09 13:27:28 +01:00
antelle 8dc7ad4f01 renamed a module 2021-01-09 13:26:19 +01:00
antelle 43c8976282 fixed a typo 2021-01-09 13:24:50 +01:00
antelle 8ee63ccc24 always using updater cache 2021-01-09 13:21:37 +01:00
antelle 2900fe07bf fixed app launch 2021-01-09 13:19:24 +01:00
antelle 1d572d1fa9 installing updates on macos 2021-01-09 13:15:25 +01:00
antelle 21b8e9ae8f removed globals 2021-01-09 11:50:40 +01:00
antelle cb77b7fc1e moved the installer script 2021-01-09 11:49:54 +01:00
antelle 763141592f fixed dev build 2021-01-09 11:48:40 +01:00
antelle 09fcddfad2 removed an old script 2021-01-09 11:44:52 +01:00
antelle b8ce1b5cc1 macos installer 2021-01-09 11:44:13 +01:00
antelle 6a34fffcc4 more options for auto-lock timeout 2021-01-08 22:56:48 +01:00
antelle 75fa636366 disabled desktop update archives 2021-01-08 22:54:45 +01:00
antelle bee96ebf15 reading update.json 2021-01-07 23:00:16 +01:00
antelle 9ec23fac5d semver test 2021-01-07 22:59:07 +01:00
antelle 2a7cd3574d update.json 2021-01-07 22:05:04 +01:00
antelle 4f96629e22 simplified perf-tracker 2021-01-07 20:54:00 +01:00
antelle 74bd270423 rename 2021-01-07 20:52:52 +01:00
antelle 0469f28a54 removed main.js 2021-01-07 20:52:43 +01:00
antelle a9c2da3fdb Merge branch 'master' into develop
# Conflicts:
#	release-notes.md
2021-01-07 20:01:20 +01:00
antelle 2ec37c3ece fixed a js error 2021-01-02 10:40:24 +01:00
antelle ef812c5697 updated keeweb-plugin dev certificate 2021-01-02 10:38:12 +01:00
antelle 8ab4e7c433 twitter link 2021-01-01 20:06:21 +01:00
antelle 23bb30be92 issue links 2021-01-01 19:57:42 +01:00
antelle a13d44d560 discussions link 2021-01-01 19:55:30 +01:00
antelle 42b5b002cc Merge branch 'release-1.16' into master
Build / darwin (push) Canceled after 0s
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
2020-12-31 17:26:37 +01:00
antelle f889488915 bump version 2020-12-31 17:26:18 +01:00
antelle 57f3a287c2 Merge branch 'release-1.16' into master 2020-12-31 17:25:58 +01:00
antelle 143b1a73f7 fix #1671: new lines removal issue in notes 2020-12-31 17:24:59 +01:00
antelle 54a1860398 removed an extra output 2020-12-30 18:17:46 +01:00
antelle 014b6b2319 added --commit-sha 2020-12-30 18:12:28 +01:00
antelle 33763ab865 fix #1670: building without git 2020-12-30 17:46:16 +01:00
antelle 5f5ea892a3 Merge branch 'master' into develop 2020-12-30 13:30:40 +01:00
antelle a3fc2b2cdd debugging windows code signing
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
2020-12-30 13:30:11 +01:00
antelle 2cad70dae0 uploading artifacts before virustotal checks 2020-12-30 13:01:55 +01:00
antelle fb56ba2f0d Merge branch 'master' into develop
# Conflicts:
#	release-notes.md
2020-12-30 13:01:12 +01:00
antelle 7c2b7a09f8 Merge branch 'master' into release-1.16 2020-12-30 13:00:41 +01:00
antelle abf5531fc5 fixed another virustotal check failure 2020-12-30 12:52:48 +01:00
antelle 18775e3cea fixed virustotal check failure 2020-12-30 12:44:48 +01:00
antelle 9d5e7be105 Merge branch 'release-1.16' into master 2020-12-30 11:35:50 +01:00
antelle eed647c867 bump version 2020-12-30 11:34:43 +01:00
antelle 072271bbe6 languages 2020-12-30 11:34:06 +01:00
antelle a84499d7d4 upgraded vulnerable dependencies 2020-12-30 11:31:37 +01:00
antelle c06db5a2b7 fix #1668: replacing more bad characters in entry fields 2020-12-30 11:30:17 +01:00
antelle fc737b1f51 fix #1665: removed a package.json dependency from keeweb-plugin 2020-12-26 11:18:48 +01:00
antelle 4f068008bd fixed issues link color 2020-12-20 18:06:20 +01:00
antelle 953f6dc61f option to disable entropy-based checks 2020-12-20 17:53:43 +01:00
antelle 01fac1f0ca password quality warnings 2020-12-20 17:44:27 +01:00
antelle 1796ac743d fixed dropdown 2020-12-19 17:33:19 +01:00
antelle 60329b3cab made the light blue background a bit better 2020-12-19 16:58:25 +01:00
antelle f489eca5c2 fix #1505: pre-selecting first field in auto-type dropdown 2020-12-19 16:47:37 +01:00
antelle 1617cae518 fixed app startup background color 2020-12-19 16:39:18 +01:00
antelle 6c7b99af58 fix #1655: separated custom icons to make the download and selection buttons more visible 2020-12-19 16:30:03 +01:00
antelle ddd242b9df fix #1655: selecting downloaded favicon automatically 2020-12-19 16:29:19 +01:00
antelle c24fe2806c contrast theme position 2020-12-19 14:05:56 +01:00
antelle 8da0a2e239 more themes 2020-12-19 14:00:51 +01:00
antelle 8aff64ce47 removed an extra border on the open view 2020-12-19 14:00:42 +01:00
antelle 677f1ce75f fix #1584: automatically switching between dark and light theme 2020-12-19 12:14:32 +01:00
antelle f99ff95a57 Merge branch 'master' into develop
# Conflicts:
#	release-notes.md
2020-12-18 20:32:44 +01:00
antelle 7a522acdd9 Merge branch 'release-1.16' into master
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
2020-12-18 20:30:46 +01:00
antelle 9888a0cf5b bump version 2020-12-18 20:27:19 +01:00
antelle 9b586f7059 bump version 2020-12-18 20:27:13 +01:00
antelle 90666cea99 GitHub funding link 2020-12-18 20:26:36 +01:00
antelle cabf0d388d using custom OneDrive without a secret 2020-12-18 20:17:34 +01:00
antelle 39a33bd77a a bit more padding in advanced search options 2020-12-17 22:38:39 +01:00
antelle f184915849 fix #1657: clear searchbox button 2020-12-17 22:22:00 +01:00
antelle 683b0bc4e6 Merge branch 'master' into develop 2020-12-17 21:15:11 +01:00
antelle 212042556f Merge branch 'release-1.16' into master
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
2020-12-17 19:29:14 +01:00
antelle cc4aa6fc1a bump version 2020-12-17 19:28:45 +01:00
antelle b4b6ef3206 calling oauth authorize again if the refresh token is expired 2020-12-17 19:25:36 +01:00
antelle ccfd5126bc release notes 2020-12-16 21:15:40 +01:00
antelle b733b43f8b release notes 2020-12-16 21:15:27 +01:00
antelle 3c0693fdd9 skip VirusTotal checks in ci-sandbox 2020-12-16 21:14:39 +01:00
antelle 938f2be487 passing sha to VirusTotal 2020-12-16 21:12:48 +01:00
antelle 9f2a09cc97 optional oauth secret 2020-12-16 20:32:48 +01:00
antelle 27d5fc4cba running VirusTotal checks on CI, see #1656 2020-12-16 20:15:14 +01:00
antelle 251b763ea9 fix #1656: false positive report on VirusTotal 2020-12-16 18:53:15 +01:00
antelle 8a07162e6b fixed checkbox positioning in settings 2020-12-12 11:02:56 +01:00
antelle 4097d81b8a fixed whitespace replacing in templates 2020-12-12 10:59:34 +01:00
antelle bf2d72745a removed the runtime chunk 2020-12-12 10:38:39 +01:00
antelle acc60e6297 Merge branch 'master' into develop 2020-12-10 23:16:06 +01:00
antelle 211b058686 Merge branch 'release-1.16' into master
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
2020-12-10 20:35:28 +01:00
antelle 95c077a0ba bump version 2020-12-10 20:34:11 +01:00
antelle 0b70017780 fix #1650: keyfiles stored in the app can't be used 2020-12-10 20:33:48 +01:00
antelle 513e258869 removed an unused workflow 2020-12-10 19:18:36 +01:00
antelle 7cd046ecc0 Merge branch 'release-1.16' into master
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
2020-12-10 19:11:47 +01:00
antelle 220a27e030 keyx 2020-12-10 19:10:18 +01:00
antelle 3728fbc367 bump version 2020-12-10 19:08:20 +01:00
antelle 6d41c71542 up 2020-12-10 19:07:54 +01:00
antelle a1b4dde3e3 release date 2020-12-10 19:06:03 +01:00
antelle 677586e882 fix #1649: missing Argon2 options 2020-12-10 17:41:59 +01:00
antelle 3177a87690 possibility to use V2 keyfiles (.keyx) 2020-12-09 19:21:18 +01:00
antelle f8fda777db Merge branch 'master' into develop 2020-12-06 10:31:16 +01:00
antelle e955c3ddc1 fix #1575: auto-type menu scrolling 2020-12-06 10:30:54 +01:00
antelle 7e36418276 fixed a js error in closing all files 2020-12-05 15:24:45 +01:00
antelle e5616dffa7 more precise license wording 2020-12-04 21:01:08 +01:00
antelle be3087d2cc removed a non-needed link 2020-12-04 20:58:10 +01:00
antelle 396721fce6 fixed a wrong copyright symbol 2020-12-04 20:57:36 +01:00
antelle d49af938d9 switched to setup-gcloud 2020-12-04 20:22:42 +01:00
antelle d2ae8522b5 release notes 2020-12-04 18:01:09 +01:00
antelle a3e27709d0 fixed local file icon 2020-12-04 16:48:48 +01:00
antelle a245553cad Merge branch 'release-1.16' into master
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
2020-12-04 16:07:25 +01:00
antelle 8bcdc6d109 bump version 2020-12-04 16:06:10 +01:00
antelle 8a1b28a793 up 2020-12-04 16:05:45 +01:00
antelle 90b236e6f9 Merge branch 'release-1.16' into master 2020-12-04 16:03:42 +01:00
antelle 804b8cf17b release notes 2020-12-04 16:03:14 +01:00
antelle ed3eefbbfc Merge branch 'master' into release-1.16 2020-12-04 16:01:55 +01:00
antelle 51564056a1 Merge branch 'develop' into master 2020-12-04 16:00:48 +01:00
antelle 4884caadd4 fixed icon positioning in links 2020-12-04 09:19:19 +01:00
antelle e129e52e01 fixed icon positioning in links 2020-12-04 09:18:23 +01:00
antelle 893a0f43c1 release date 2020-12-04 08:55:22 +01:00
antelle 083cbe9840 release date 2020-12-04 08:16:27 +01:00
antelle a7fcbae65f up native modules 2020-12-04 07:25:29 +01:00
antelle 7ae80c2e7c copyrights 2020-12-03 23:57:40 +01:00
antelle f1ede2b876 license year 2020-12-03 23:31:42 +01:00
antelle 8c51adbca1 up node_modules 2020-12-03 22:12:52 +01:00
antelle 446f293da0 rebuilt KeeWebHelper as a universal app 2020-12-03 22:12:42 +01:00
antelle bbd7f9c6d6 keyfile paths are saved by default, see #325 2020-12-03 21:09:51 +01:00
antelle 9e5fb90bd6 Argon2id KDF support 2020-12-03 20:22:33 +01:00
antelle 2ed735ad95 fixed list borders on mobile 2020-12-02 21:01:56 +01:00
antelle 00be6f0181 fixed default theme 2020-12-01 19:53:18 +01:00
antelle 29a4d367f9 added missing rgba 2020-12-01 19:42:37 +01:00
antelle df43c61785 fix #1645: color contrast on the selection 2020-12-01 19:28:07 +01:00
antelle 464c49257a building arm64.dmg 2020-11-30 21:16:17 +01:00
antelle bd4a6d0eee fixed arm64 2020-11-30 21:03:20 +01:00
antelle 9410fc6a8c apple silicon build 2020-11-30 20:52:09 +01:00
antelle bd400c0797 up native modules 2020-11-30 18:51:26 +01:00
Dimitri Witkowski 54c721c265 Merge pull request #1642 from PeterDaveHello/DockerfileRefactor
Clean up apt local cache in Dockerfile
2020-11-30 07:49:33 +01:00
Peter Dave Hello 94cfa4f3d4 Replace ADD with COPY instruction in Dockerfile
Reference:

- https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#add-or-copy

> For other items (files, directories) that do not require ADD’s tar
> auto-extraction capability, you should always use COPY.
2020-11-30 10:11:32 +08:00
antelle f21ef7f444 fixed min electron version 2020-11-29 19:58:34 +01:00
Dimitri Witkowski 66a0cf4782 Merge pull request #1639 from PeterDaveHello/patch-3
Ask apk to leave no cache in Dockerfile
2020-11-29 18:57:12 +01:00
Dimitri Witkowski 52f27ce743 Merge pull request #1638 from PeterDaveHello/patch-2
Clean up apt local cache in Dockerfile
2020-11-29 18:56:38 +01:00
Peter Dave Hello 57296ba313 Ask apk to leave no cache in Dockerfile
This will make the image smaller
2020-11-30 01:51:47 +08:00
Peter Dave Hello 47dc1727df Clean up apt local cache in Dockerfile
This will make the image smaller
2020-11-30 01:49:53 +08:00
antelle cd9fe46fdb fixed jumping title in Safari 2020-11-29 18:06:56 +01:00
antelle 775cdf237c fix #1637: git commit in the About box 2020-11-29 17:10:56 +01:00
antelle 63367998bf Merge branch 'develop' into master
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
2020-11-29 15:06:59 +01:00
antelle 5d3e110a9e release notes 2020-11-29 15:05:47 +01:00
antelle 42267eaef8 languages 2020-11-29 15:05:15 +01:00
antelle b716599c90 up deps 2020-11-29 14:53:21 +01:00
antelle 6d80de9216 bump version 2020-11-29 14:48:43 +01:00
antelle 212dc99cec updated screenshot 2020-11-29 14:44:39 +01:00
antelle 6f4f8ec1ea action names 2020-11-29 14:12:42 +01:00
antelle 24c64daa49 gcloud action 2020-11-29 13:29:01 +01:00
antelle bdd9a51d25 style fixes 2020-11-29 13:12:32 +01:00
antelle f27862b036 mac menubar icon 2020-11-29 12:17:49 +01:00
antelle f7e9f725b0 bugfixes 2020-11-29 11:10:34 +01:00
antelle 4ee430284b some fixes 2020-11-29 00:19:49 +01:00
antelle 96458048fc fixed menu color 2020-11-28 23:43:56 +01:00
antelle a31f9d5a50 new themes 2020-11-28 23:38:12 +01:00
antelle 33d5f0b5bb some icon fixes 2020-11-28 12:30:46 +01:00
antelle ec43f0a549 fixed themes grid size 2020-11-27 22:28:10 +01:00
antelle 8e0dc326cb better theme selector 2020-11-27 21:17:27 +01:00
antelle 9994c87446 default locale in settings 2020-11-27 20:21:24 +01:00
antelle 647ce573b0 set the default language to en-US to reflect what it is 2020-11-27 18:47:55 +01:00
antelle 1ca4ead313 release notes 2020-11-27 18:40:52 +01:00
antelle 1ef5ffab52 Merge branch 'MrSnix-feature/time-format' into develop 2020-11-27 18:40:05 +01:00
antelle f4f2ddfb3c fix 2020-11-27 18:38:11 +01:00
antelle 650b4805be fixed test runner fatal error reporting 2020-11-26 23:34:08 +01:00
antelle 22754f32ec revert 2020-11-26 23:33:37 +01:00
antelle 85a67b533a fixed test runner fatal error reporting 2020-11-26 22:27:20 +01:00
antelle 974dbd224a release notes 2020-11-26 22:04:06 +01:00
antelle b8c7a8b936 fixed the yubikey icon 2020-11-26 22:04:06 +01:00
antelle 86844064db updated macOS helper icon 2020-11-26 22:04:05 +01:00
antelle 0c9b9a1b97 removed app icon for macos 2020-11-26 22:04:01 +01:00
Giuseppe 0a9846b86f Fix: wrong argument passed 2020-11-26 21:41:24 +01:00
Giuseppe 96ee17b8cc Moved date-format.js to comp/util/ 2020-11-26 21:19:36 +01:00
Giuseppe 4b65792585 Tests now are UTC based to avoid locale conflicts 2020-11-26 20:48:43 +01:00
Giuseppe 32b871e338 Forgot to remove useless import 2020-11-26 11:45:47 +01:00
Giuseppe 46ddb725db Initial commit 2020-11-26 11:32:10 +01:00
antelle d0fdada9f7 release notes 2020-11-25 23:45:14 +01:00
antelle a343853b38 fixed the yubikey icon 2020-11-25 23:33:45 +01:00
antelle 136fbc2f77 updated macOS helper icon 2020-11-25 23:29:43 +01:00
antelle 25bc5643b1 removed app icon for macos 2020-11-25 23:21:29 +01:00
antelle a0c03363a7 removed an old favicon 2020-11-25 22:50:35 +01:00
antelle 8dd7a97769 removed a comment 2020-11-25 21:51:32 +01:00
antelle f70dfaaa28 icons adjustment 2020-11-25 21:40:54 +01:00
antelle 01ceb6dc37 replaced an icon 2020-11-25 21:07:07 +01:00
antelle d56e50b29d reverted the onedrive icon 2020-11-25 20:14:40 +01:00
antelle 0b2c722f61 replaced some icons 2020-11-25 20:10:37 +01:00
antelle 26990f38dd new pinned tab icon 2020-11-25 19:38:17 +01:00
antelle b2d87efc99 yubikey image 2020-11-25 18:28:26 +01:00
antelle 63b7b32e9c fontawesome 5 2020-11-25 18:20:53 +01:00
antelle 8925a48822 bugfix 2020-11-24 18:04:30 +01:00
antelle 8ad47181a9 removed an old edge hack 2020-11-24 17:54:04 +01:00
antelle c1b9ec7a77 icon 2020-11-23 23:39:04 +01:00
antelle 6daf34e261 new icon 2020-11-22 12:25:43 +01:00
antelle fc5c865b18 disabled contextIsolation 2020-11-20 20:46:01 +01:00
antelle 083306a1cd google-github-actions 2020-11-20 15:24:20 +01:00
antelle 5ebacbc347 building on node.js 15 2020-11-20 14:53:28 +01:00
antelle 08c4adfd46 fixed tests 2020-11-20 14:48:53 +01:00
antelle 27f87ad09f get-git-tag 2020-11-20 14:47:14 +01:00
antelle d0b33ca0c1 fix #1523: support for WebDAV servers without Last-Modified header 2020-11-20 14:08:13 +01:00
antelle bb44c7cb3e fixed some that=this 2020-11-20 13:12:06 +01:00
antelle 66e366d9d0 fix #1615: restoring the app window if it's activated when minimized 2020-11-20 10:29:47 +01:00
antelle 31390eac80 fix #1555: auto-saving files when minimize options is enabled 2020-11-19 23:37:09 +01:00
antelle 543a71f6f2 up deps 2020-11-19 18:43:50 +01:00
antelle 5d29b79dab bump electron 2020-11-19 16:52:27 +01:00
antelle 207ff77778 fix #1599: switched to Dropbox short-lived access tokens 2020-11-19 16:05:08 +01:00
antelle b85d25614b fix #1616: auto-type with no matching entries 2020-11-19 13:00:56 +01:00
antelle d1bcdca0d3 fix #1619: auto-locking ignored a field being edited 2020-11-19 11:21:45 +01:00
antelle ffb68b1651 fix #1561: error during loading configs after reset 2020-11-19 11:12:36 +01:00
antelle 49d46cfedc fixed YubiKey errors display 2020-11-11 23:08:08 +01:00
antelle 9c18e2877b fix #1589: shortcut to copy OTP 2020-11-11 19:01:12 +01:00
antelle a1da5ceabe fix #1608: improved the "Show all file" checkbox behavior 2020-11-11 18:44:57 +01:00
antelle 759b92bfd6 fixed a performance issue in searching entries 2020-11-10 23:19:26 +01:00
antelle b4f3d19259 Merge branch 'master' into develop 2020-11-09 21:35:57 +01:00
antelle 35e3271839 added a check for safety 2020-10-28 20:18:27 +01:00
antelle 90da86ebb8 fix #1621: colors on Linux 2020-10-28 20:17:13 +01:00
antelle ad978d2ed3 fix #1612: added WebCrypto check back 2020-10-02 18:07:46 +02:00
antelle 7140a2d894 npm i
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
2020-09-12 12:23:51 +02:00
antelle eb86603b47 Merge branch 'release-1.15' into master 2020-09-12 12:17:03 +02:00
antelle 1e1117c28b updated vulnerable dependencies 2020-09-12 12:16:41 +02:00
antelle f3de0d8391 Merge branch 'release-1.15' into master 2020-09-12 12:12:28 +02:00
antelle 4749be20b4 bump version 2020-09-12 12:10:15 +02:00
antelle 3eea00bf6d release notes 2020-09-12 12:06:38 +02:00
antelle d301287fdc readme 2020-09-12 12:05:45 +02:00
antelle 07f4090498 readme 2020-09-12 12:04:27 +02:00
antelle 067d3778d8 PKCE enabled on Dropbox 2020-09-12 12:04:16 +02:00
antelle daa250e8fa fix 1597: dropbox 2020-09-12 12:03:20 +02:00
antelle 91f992df39 up kdbxweb, fix #1591, fix #1598 2020-09-12 11:30:15 +02:00
antelle ecaf9a37da prettier 2020-09-09 21:42:37 +02:00
antelle 31cc2fbdd4 Merge branch 'opennomad-linux_auto_type' into release-1.15 2020-09-09 21:40:58 +02:00
Matthias Johnson 6e30687919 use windowactivate via xdotool 2020-09-08 12:31:33 -06:00
antelle dbf212f0df Merge branch 'master' into develop
# Conflicts:
#	release-notes.md
2020-08-08 14:29:11 +02:00
antelle af49645f8d Merge branch 'release-1.15'
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
2020-08-08 14:25:41 +02:00
antelle 59bed7593d fix #1581: double-clicking KeeWeb icon in Dock 2020-08-08 14:24:47 +02:00
antelle 43ca723c75 bump version 2020-08-08 14:23:42 +02:00
antelle 855370074f fix #1553: empty fields display for templates 2020-08-08 14:11:12 +02:00
antelle 84f707d6cd fix #1581: double-clicking KeeWeb icon in Dock 2020-08-08 12:20:08 +02:00
antelle 17be9cf266 removed some old stuff from v1.15 2020-06-21 13:04:09 +02:00
antelle 0e3d01ade6 always using native argon2 in desktop 2020-06-21 13:02:06 +02:00
antelle 02fe2b1754 Merge branch 'hesalx-fix-macos-quit' into release-1.15 2020-06-15 17:46:18 +02:00
hesalx a0c553b3a9 allow the app to quit when not minimized and window is closed 2020-06-15 11:32:48 +03:00
antelle 62ea631269 Merge branch 'release-1.15'
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
2020-06-13 19:30:36 +02:00
antelle b32d842394 bump version 2020-06-13 13:08:32 +02:00
antelle 0c38b5b9f1 fixed exe code signing 2020-06-13 13:08:16 +02:00
antelle dd0b20634c release notes 2020-06-13 13:08:09 +02:00
antelle f8319408f1 don't clear cache from the ci sandbox 2020-06-13 13:08:00 +02:00
antelle c451e92a9c fixed exe code signing 2020-06-13 12:31:48 +02:00
antelle 36cf70202d Merge branch 'master' into develop
# Conflicts:
#	desktop/app.js
#	release-notes.md
2020-06-13 12:30:48 +02:00
antelle 39fe83fdd1 Merge branch 'release-1.15'
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
2020-06-13 10:54:59 +02:00
antelle cc5a465dc3 up 2020-06-13 10:54:31 +02:00
antelle 2018f04bdf fixed exports 2020-06-13 10:54:10 +02:00
antelle f0e79eab95 Merge branch 'release-1.15' 2020-06-13 10:25:22 +02:00
antelle fc1b2fbbaa fix #1532: crashes on some Windows version (updated electron) 2020-06-13 08:49:59 +02:00
antelle a8e89da5e9 up deps 2020-06-13 08:48:37 +02:00
antelle e369a6b7be bump version 2020-06-12 21:15:58 +02:00
antelle ae4d4398cd fix #1536: added a missing dependency on linux 2020-06-12 21:15:36 +02:00
antelle 5781d20615 Merge branch 'release-1.15'
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
2020-06-11 19:54:52 +02:00
antelle a6e9521435 bump version 2020-06-11 19:53:53 +02:00
antelle 1e72711bc3 bump version script 2020-06-11 19:53:33 +02:00
antelle 1f793e2d00 bump version script 2020-06-11 19:53:21 +02:00
antelle af8d94d102 fix #1535: network errors in Dropbox and GDrive on Windows 2020-06-11 19:48:30 +02:00
antelle a424c3286a extracting files after signing 2020-06-10 20:27:55 +02:00
antelle 5f9b33506a Merge branch 'master' into release-1.15 2020-06-09 21:04:48 +02:00
antelle 819b10e1f6 fixed version
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
2020-06-09 21:02:08 +02:00
antelle 0c170766e5 Merge branch 'release-1.15' 2020-06-09 20:47:36 +02:00
antelle f7a0025b97 bump version 2020-06-09 20:47:07 +02:00
antelle 22776e9088 fix #1409: auto-type wrong character issues on Linux 2020-06-09 20:39:09 +02:00
antelle d23d393c39 - fixed duplicated YubiKeys displayed in file settings 2020-06-09 19:50:35 +02:00
antelle bbf6e796f8 updated electron version 2020-06-09 19:46:37 +02:00
antelle 1c3c194b3a possibility to debug startup with --start-logging 2020-06-09 19:36:18 +02:00
antelle 0cc633c5c1 added a possibility to log messages on startup 2020-06-09 19:35:17 +02:00
antelle 9a8f1ad508 fix #1530: running from directories with hash symbols 2020-06-09 19:26:59 +02:00
antelle 65f09c6535 fix #1530: running from directories with hash symbols 2020-06-09 19:26:41 +02:00
antelle d7db5d2c77 removed some debugging code 2020-06-09 19:09:37 +02:00
antelle 8205b01c65 added temporary debug logging 2020-06-08 22:58:11 +02:00
antelle d7ee936b27 fix #1530: recursive creation of the portable directory 2020-06-08 19:13:34 +02:00
antelle d9ae6f312f fix #1530: recursive creation of the portable directory 2020-06-08 19:12:59 +02:00
antelle aea9a513b4 removed a non-working link 2020-06-07 16:55:42 +02:00
antelle d3b65f6280 added a vimeo link 2020-06-07 13:53:15 +02:00
antelle 3bf53aa87f Merge branch 'master' into develop 2020-06-07 12:33:31 +02:00
antelle 5081df4f2f Merge branch 'master' into release-1.15 2020-06-07 12:33:10 +02:00
antelle b91dbdaa8f purging cloudflare cache after publishing a release 2020-06-07 12:32:22 +02:00
antelle c313de9f93 release date
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
2020-06-07 11:04:57 +02:00
antelle 09b00f3137 Merge branch 'release-1.15' 2020-06-07 11:03:39 +02:00
antelle 8342336e8d bump version 2020-06-07 09:48:23 +02:00
antelle fe245dc95e fix #1528: OTP generation for stored values 2020-06-07 09:47:36 +02:00
antelle 3001afd9db Merge branch 'develop'
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
2020-06-06 16:50:23 +02:00
antelle 48b5c8d4e7 up deps 2020-06-06 16:48:48 +02:00
antelle 21dc4e758f bump version 2020-06-06 16:47:32 +02:00
antelle 5c5fc0271e languages 2020-06-06 16:43:13 +02:00
antelle 082c6bee93 moved native modules to a native module host 2020-06-06 13:30:35 +02:00
antelle c1d354a6fb added an error when usb is disabled 2020-06-05 20:37:13 +02:00
antelle eab683ec71 removed all mentions of cordova
It never got enough love by contributors and it seems to be abandoned. Better to
implement this API in a separate repo.
2020-06-05 16:45:37 +02:00
antelle cd2b87b317 fixed refreshing the yubikey status 2020-06-05 16:41:54 +02:00
antelle 4abe63c00f fixed ykman path on macos 2020-06-05 16:41:38 +02:00
antelle 7e4e61e005 fixed ykman path on macos 2020-06-04 21:33:42 +02:00
antelle db38e015f8 option to skip code signing on macos 2020-06-04 20:13:15 +02:00
antelle ff20d2a554 up kdbxweb 2020-06-04 18:49:33 +02:00
antelle cb7df205bb up deps 2020-06-03 22:42:39 +02:00
antelle dfe2c42172 utils sh 2020-06-03 21:31:32 +02:00
antelle 4854c0c100 removed an unnecessary task 2020-06-03 21:28:31 +02:00
antelle 33bdf124c2 up languages 2020-06-03 21:27:17 +02:00
antelle 2d752ef144 fix #917: option to install without a desktop icon on Windows 2020-06-03 18:11:38 +02:00
antelle d258bce037 de 2020-06-03 11:31:40 +02:00
antelle 21ff37d82e workflow 2020-06-03 09:58:57 +02:00
antelle 312b08ca99 workflow 2020-06-03 09:58:39 +02:00
antelle a47f0d0ae5 up 2020-06-03 09:51:47 +02:00
antelle c1a6268c2d added some logging 2020-06-03 08:33:26 +02:00
antelle 65b6fe2e2e removed an old task 2020-06-02 22:30:21 +02:00
antelle 0f29e94272 default format for new files is now KDBX4 2020-06-02 21:57:41 +02:00
antelle dd9b6a1943 disabled codeql-analysis 2020-06-02 19:33:06 +02:00
antelle a45bc13248 override language detection 2020-06-02 19:26:59 +02:00
antelle b7b5caac9d trying out codeql-analysis 2020-06-02 19:22:27 +02:00
antelle 0eb5ebab0d wording 2020-06-02 19:14:48 +02:00
antelle f34b1011c8 more contributions 2020-06-02 17:48:09 +02:00
antelle 33049c21e7 contribution links 2020-06-02 17:39:03 +02:00
antelle 6c12822279 contribution links 2020-06-02 17:37:20 +02:00
antelle 8a3ff150a6 added contributions 2020-06-02 17:36:13 +02:00
antelle de4bfdf9e0 reformatted build.yaml 2020-06-02 14:16:06 +02:00
antelle 461a45dc51 packaging native dependencies separately 2020-06-02 13:58:25 +02:00
antelle 2b24d716a9 up deps 2020-06-02 13:00:17 +02:00
antelle 36b6fd80b8 added a comment to the workflow 2020-06-02 12:56:27 +02:00
antelle f8cbf51842 skipping code signing on windows 2020-06-02 12:43:05 +02:00
antelle 17fbf9188d option to skip code signing on Windows 2020-06-02 12:41:30 +02:00
antelle ec5bacd951 updated the workflow 2020-06-02 12:29:55 +02:00
antelle 56c8649040 up yk-api 2020-06-02 12:23:22 +02:00
antelle 435eb5779f fixed some portable installation issues on macos 2020-06-02 10:47:20 +02:00
antelle a83e04fe4d reverted config changes 2020-06-01 23:54:55 +02:00
antelle bdbff334a5 syntax for old node.js 2020-06-01 23:30:33 +02:00
antelle f70eb35f69 syntax for old node.js 2020-06-01 23:27:48 +02:00
antelle f1a5aba485 refactored codesignconfig 2020-06-01 22:54:38 +02:00
antelle f8e454dab3 splitted macos app signing and notarization 2020-06-01 22:51:42 +02:00
antelle 9988454af1 fixed app exit while the app is not ready 2020-06-01 16:59:32 +02:00
antelle e0b65bbebf up modules; prettier 2020-06-01 16:53:51 +02:00
antelle 09fd37820b bumped min electron version 2020-06-01 16:46:21 +02:00
antelle 360194c627 loading native modules from updated desktop archives 2020-06-01 16:45:18 +02:00
antelle 21768b1b59 testing builds 2020-06-01 15:55:52 +02:00
antelle 325d521f49 fix #448: minimized login option support on macOS 2020-06-01 15:02:19 +02:00
antelle 2deb241ff2 fix #830: minimize instead of close option on macOS 2020-06-01 14:42:06 +02:00
antelle a2194435e6 fix #1460: auto-type on double-clicking field labels 2020-06-01 10:25:16 +02:00
antelle 448e173f7e added a warning about Input Monitoring for mac 2020-06-01 07:30:00 +02:00
antelle 4b52280549 fixed sticky tips 2020-05-31 23:31:14 +02:00
antelle 9e09f7b7e7 fixed double yubikey alert when opening files from storages 2020-05-31 22:28:38 +02:00
antelle 83293d909e up 2020-05-31 20:26:48 +02:00
antelle 176553a674 fixed challenge-response calculation with padding 2020-05-31 16:35:36 +02:00
antelle a4b22b6c88 silenced the deprecation warning 2020-05-31 14:25:50 +02:00
antelle fb6bcdf5c9 added a possibility to refresh the list of yubikeys 2020-05-31 14:23:37 +02:00
antelle 776c75d823 grammar 2020-05-31 14:13:32 +02:00
antelle 143f7c6a7a yubikey enrollment 2020-05-31 14:13:08 +02:00
antelle b520c58ef4 cancelChalResp 2020-05-31 13:06:36 +02:00
antelle 3c47adbf32 fixed argon2 in browsers 2020-05-31 13:03:59 +02:00
antelle 835acff637 up 2020-05-31 13:00:35 +02:00
antelle a08e3c7d27 option to remember challenge-response codes 2020-05-31 10:15:27 +02:00
antelle d9258745d0 fixed file saving errors 2020-05-30 23:28:33 +02:00
antelle 70bd4f1c4e fixed main window close/closed events confusion 2020-05-30 17:46:13 +02:00
antelle ab3860cdc9 fixed errors during auto-save 2020-05-30 17:40:18 +02:00
antelle 9185ef9a55 showing main window for yubikey alerts 2020-05-30 17:12:48 +02:00
antelle e6826b176e yubikey ui alerts 2020-05-30 16:02:02 +02:00
antelle f5bb29e61a fixed open args 2020-05-30 14:28:06 +02:00
antelle d0d013e046 clearing cache on file close 2020-05-30 12:45:56 +02:00
antelle 5002c2ce67 better building instructions 2020-05-30 12:06:53 +02:00
antelle 8e3b218a74 readme 2020-05-30 12:02:04 +02:00
antelle 51bd80faf4 fixed saved yubikeys 2020-05-30 10:29:02 +02:00
antelle b4fe0af53a extracted challenge-response calculator 2020-05-30 08:19:47 +02:00
antelle 2ba9a03e2c using yubikeys for opening files 2020-05-30 08:10:19 +02:00
antelle 7394754b6f fixed an error when files were closed during sync 2020-05-30 07:47:52 +02:00
antelle b41b291e60 added desktop module description 2020-05-30 07:39:31 +02:00
antelle 0f582e3248 refreshing the list of yubikeys on the start screen 2020-05-29 23:24:05 +02:00
antelle b90e84be42 loading yubikeys using a native module 2020-05-29 23:15:10 +02:00
antelle ef627c9530 updated keeweb-native-modules 2020-05-29 21:49:33 +02:00
antelle b3f021a577 fixed eslint 2020-05-28 18:34:32 +02:00
antelle 96263c11ec escaping more characters in xml, see #1520 2020-05-28 10:54:52 +02:00
antelle b2a6e1180c reverted renderer process native modules, it crashes 2020-05-28 10:48:09 +02:00
antelle 817b44b152 fixed an error during loading the list of yubikeys 2020-05-26 23:26:26 +02:00
antelle 701bb4caa4 loading compatible modules in renderer process 2020-05-26 23:24:00 +02:00
antelle a1b8682316 moved the stuck yubikey flag to the otp section 2020-05-25 19:40:04 +02:00
antelle 8c386dbe57 challenge-response calculation function 2020-05-24 21:06:53 +02:00
antelle d8e49d993a added a text about used yubikey 2020-05-24 20:31:03 +02:00
antelle 93310eb029 listing YubiKeys on the open view 2020-05-24 20:02:49 +02:00
antelle f215c26a63 removed plugin cache invalidation with timestamps 2020-05-24 19:07:01 +02:00
antelle b5fddeb627 added a missing check 2020-05-24 18:42:14 +02:00
antelle 81d4c5c403 extracted YubiKey module 2020-05-24 18:39:56 +02:00
antelle bf7dec2437 fixed writing unencrypted configs 2020-05-24 13:46:03 +02:00
antelle efa9b5f9a7 fixed the yubikey challenge-response icon on the open screen 2020-05-23 19:26:54 +02:00
antelle 1f862a37e9 fixed yubikey icon on the open screen 2020-05-23 19:07:45 +02:00
antelle e8a491dba5 disabled sandbox mode in package.json/electron 2020-05-23 17:08:55 +02:00
antelle aa899b8096 fix #1409: fixed auto-typing Tab character on Debian 2020-05-23 17:07:59 +02:00
antelle 8de55c450a fixed sticky tooltips in settings 2020-05-22 22:44:50 +02:00
antelle 1fafa68793 restructured settings code a bit 2020-05-22 22:28:12 +02:00
antelle e69219697a serializing settings in renderer 2020-05-22 22:17:36 +02:00
Dimitri Witkowski 08a0f6e587 Merge pull request #1514 from b3nj5m1n/add_check_support_windowid
Added check for system supporting window id
2020-05-22 21:48:06 +02:00
b3nj5m1n 7a26d80255 Removed log from debugging 2020-05-22 21:10:52 +02:00
b3nj4m1n 4171848655 Added check for system supporting window id 2020-05-22 21:05:30 +02:00
antelle a7193fd783 fixed config writing 2020-05-22 20:55:05 +02:00
antelle ccce95d4fe fixed configs for portable installations 2020-05-22 20:54:47 +02:00
antelle b9f37c22d9 config encryption with a key from keychain 2020-05-22 20:46:03 +02:00
Dimitri Witkowski 3b3c95e57c Merge pull request #1513 from b3nj5m1n/fix_app_dock
Added check for platform before calling app.dock
2020-05-22 18:58:50 +02:00
b3nj4m1n fadea36232 Added check for platform before calling app.dock 2020-05-22 18:47:26 +02:00
antelle 99b687244c release notes: fix #1509: fixed auto-type for tiling mode in Linux 2020-05-22 12:34:31 +02:00
antelle 813b26270f extracted a constant 2020-05-22 12:30:01 +02:00
antelle b715507dd0 Merge branch 'b3nj5m1n-autotype-tilingwm' into develop 2020-05-22 12:25:11 +02:00
b3nj4m1n 0cb502ca67 Fixed possible error for undefined window id 2020-05-22 12:10:27 +02:00
antelle e5073eb65f default theme on macOS 2020-05-22 11:44:49 +02:00
antelle c3b55cd7fa better portable app checks 2020-05-22 10:56:08 +02:00
antelle e9ef1bd698 fixed remote events 2020-05-22 10:44:59 +02:00
antelle 045fe99158 made dropbox secret hidden 2020-05-22 10:15:21 +02:00
antelle dad95033c0 added a possibility to clear a storage provider field in app settings 2020-05-22 10:14:43 +02:00
b3nj4m1n 02e4d52db6 windowId gets passed in a different place 2020-05-21 21:36:26 +02:00
b3nj4m1n 1f83f34e55 Addressed requested changes 2020-05-21 19:41:19 +02:00
b3nj4m1n 1ffb45433c Fixed auto-type on tiling wm 2020-05-21 17:10:32 +02:00
antelle b6780dff03 ignored tags for yubikey entries 2020-05-16 10:03:02 +02:00
antelle 5b91dcb272 fix #1440: fixed auto-type for maximized windows 2020-05-15 22:41:39 +02:00
antelle 099f1ca9d0 calling openDevTools from window.webContents 2020-05-15 21:54:34 +02:00
antelle c73f81a80a dev desktop tasks 2020-05-15 21:38:33 +02:00
antelle 177b150c95 Merge branch 'master' into develop
# Conflicts:
#	app/templates/export/entry.hbs
#	release-notes.md
2020-05-15 20:52:16 +02:00
antelle 489eb5598c Merge branch 'release-1.14'
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
2020-05-15 20:37:24 +02:00
antelle ad571c1e27 fix eslint 2020-05-15 20:36:59 +02:00
antelle 9827b871fc Merge branch 'release-1.14' 2020-05-15 20:26:25 +02:00
antelle 004436e868 bump version 2020-05-15 20:25:57 +02:00
antelle 008b615903 improved exporting files with markdown notes 2020-05-15 20:25:22 +02:00
antelle 451b465e4f disabled markdown in export 2020-05-15 20:17:40 +02:00
antelle c91e5de961 readme formatting 2020-05-15 20:14:55 +02:00
antelle 8251423d95 up deps 2020-05-15 20:00:18 +02:00
antelle 65f66ac60c fix #1503: arm64 Windows installer 2020-05-14 22:59:11 +02:00
antelle 94caa1fca3 fix #1503: building windows arm64 2020-05-14 20:52:02 +02:00
antelle f7d1708550 removed pcsclite 2020-05-14 20:47:11 +02:00
antelle b888f9da32 ignored unnecessary native modules 2020-05-14 20:36:14 +02:00
antelle 4d678184f3 option to create a portable installation 2020-05-14 20:11:41 +02:00
antelle a2bf157b01 fixed portable executable dir 2020-05-14 18:55:11 +02:00
antelle 1b279119cb auto-opening yubikeys with other files 2020-05-14 18:31:26 +02:00
antelle 2075e82381 increased the yubikey reconnect timeout 2020-05-13 22:29:12 +02:00
antelle 9f60ca8ece fix #1506: replaced incorrectly added client secret config properties 2020-05-13 22:25:33 +02:00
antelle d6867fb62e added native modules links 2020-05-13 21:25:43 +02:00
antelle 07e918965b fix #620: clearing middle-click clipboard in Linux 2020-05-13 21:20:26 +02:00
antelle 24bcc758e7 release notes 2020-05-13 20:26:25 +02:00
antelle 7ae64b0552 fixed native argon2 2020-05-13 20:25:45 +02:00
antelle 38e46f6d85 building native modules into asar 2020-05-13 20:25:33 +02:00
antelle 530316c25f native modules for all available architectures 2020-05-13 19:15:56 +02:00
antelle cc750df077 moved native modules to the main process 2020-05-13 17:44:33 +02:00
antelle 3c85694fc2 removed temp paths from profile 2020-05-13 17:03:23 +02:00
antelle 955a1346ff removed old cookie handling 2020-05-13 16:37:35 +02:00
antelle 8e4566fe5f moved app options 2020-05-12 23:46:19 +02:00
antelle 20623e4c42 disabled unnecessary caching 2020-05-12 23:10:26 +02:00
antelle cac31d3350 added a yubikey selection icon to the open screen 2020-05-11 19:29:39 +02:00
antelle 746b56ac57 release notes 2020-05-11 19:11:14 +02:00
antelle bc140b3fb5 auto-opening yubikeys 2020-05-11 18:49:21 +02:00
antelle 5d15411d3d fixed sequential otp generation 2020-05-11 17:44:18 +02:00
antelle c6ce694dfe displaying matching otp codes in entries 2020-05-11 17:24:06 +02:00
antelle 16d303d966 fixed password field after idle period 2020-05-10 19:44:29 +02:00
antelle f422dbd3db fixed variable name 2020-05-10 16:48:58 +02:00
antelle 5125a44170 added enter to the default totp command 2020-05-10 11:42:13 +02:00
antelle 6e7f2c570f fixed dev app icon 2020-05-10 09:49:09 +02:00
antelle db31e65cdf fixed entry creation on a yubikey 2020-05-09 23:55:57 +02:00
antelle 3cd9bf6505 html => empty 2020-05-09 20:15:46 +02:00
antelle 3b05f6267e escaping fields autocomplete 2020-05-09 17:00:39 +02:00
antelle 3e5b0bff4f renamed content to contentHtml 2020-05-09 16:39:04 +02:00
antelle c9cb15d7b7 removed shortcuts formatting 2020-05-09 16:35:11 +02:00
antelle 89415c86a4 escaping details shortcuts 2020-05-09 16:18:39 +02:00
antelle 4cd515b19f put export csp back 2020-05-09 16:16:27 +02:00
antelle 730e2c5ba5 removed export csp 2020-05-09 16:14:56 +02:00
antelle 3735a6689c escaping attachments 2020-05-09 16:14:43 +02:00
antelle 15c81d8f35 partials support 2020-05-09 16:14:20 +02:00
antelle 154c780281 disabled markdown in export 2020-05-09 15:25:11 +02:00
antelle ec9422d22d added csp for exported html 2020-05-09 14:39:18 +02:00
antelle 101e8eaa24 fixed sort options 2020-05-09 10:59:23 +02:00
antelle 6a31bba69c using optional chaining 2020-05-09 10:45:12 +02:00
antelle 96ee68dee7 fixed yubikey totp auto-type 2020-05-09 10:37:34 +02:00
antelle 5a94c81b11 fixed yubikey username auto-type 2020-05-09 08:57:57 +02:00
antelle cf8aa6f9a4 copying otp from yubikeys 2020-05-08 23:33:57 +02:00
antelle 20e201795e options for yubikey username field 2020-05-08 23:16:13 +02:00
antelle e95902d2bb wording: one-time codes 2020-05-08 23:15:38 +02:00
antelle 79a3b39248 disabled KEEWEB_HTML_PATH in prod builds 2020-05-08 16:20:23 +02:00
antelle c08a0eb8d1 fixed the details view 2020-05-07 23:10:35 +02:00
antelle a280258d4f cleaned up openProcess 2020-05-07 23:10:23 +02:00
antelle 7985a7a522 added a better message when a yubikey is stuck 2020-05-07 22:07:58 +02:00
antelle 6ba2e16a91 fixed yubikey reconnection 2020-05-07 21:22:34 +02:00
antelle f34ebe2fd3 code cleanup 2020-05-07 19:00:18 +02:00
antelle ab3d4a056f fixed the yubikey workaround 2020-05-07 18:58:17 +02:00
antelle c88a7c000b extracted a method 2020-05-06 23:12:49 +02:00
antelle 53b700aa70 fixed yubikey serial detection 2020-05-06 23:06:22 +02:00
antelle 66c219f6d1 locale 2020-05-06 21:08:37 +02:00
antelle 06dd153955 fixed stuck yubikeys 2020-05-06 21:06:19 +02:00
antelle 88a0e63894 disabled auto-open by default 2020-05-06 19:49:21 +02:00
antelle cac7e53ea8 fixed work with several yubikeys 2020-05-06 19:30:30 +02:00
antelle 3e390388eb removed a workaround for Edge 2020-05-06 18:44:00 +02:00
antelle 2a1b01c0aa displaying last open file after detaching a yubikey 2020-05-06 18:43:04 +02:00
antelle 5a535bb07a Added a yubikey workaround 2020-05-06 18:37:37 +02:00
antelle 235ceae228 restarting the yubikey application if it's stuck 2020-05-05 22:36:23 +02:00
antelle 46710aead4 watching yubikeys 2020-05-05 21:26:41 +02:00
antelle 277d443d4c Merge branch 'usb' into develop 2020-05-05 20:58:20 +02:00
antelle 770c25a273 fixed open files 2020-05-05 20:57:26 +02:00
antelle c935de3ec1 message 2020-05-05 20:51:01 +02:00
antelle 8350123839 devices 2020-05-05 20:50:11 +02:00
antelle 02adb81ae0 settings 2020-05-05 20:47:15 +02:00
antelle cf26427e68 fix otp cancel 2020-05-05 20:14:32 +02:00
antelle 6e357e93ec props 2020-05-05 20:03:38 +02:00
antelle 1c8f3932fb search fix 2020-05-05 18:11:58 +02:00
antelle 75671a0a8a canUseNativeModules 2020-05-05 18:01:16 +02:00
antelle 58296dd896 disabled yubikey on win32 2020-05-05 17:57:01 +02:00
antelle 2fff34dc61 grammar 2020-05-05 17:49:19 +02:00
antelle 851ade7e24 fixed drag 2020-05-05 17:46:07 +02:00
antelle 13585f5317 splitted detail fields 2020-05-05 17:28:20 +02:00
antelle 5d0ab36f2c fixed details 2020-05-05 17:05:20 +02:00
antelle be46cf9a25 lint fix 2020-05-05 16:37:25 +02:00
antelle ffdc438091 removed app-model prepare 2020-05-05 16:34:39 +02:00
antelle 52741cf46a search tests 2020-05-05 16:23:17 +02:00
antelle 9263caed59 search 2020-05-05 15:08:19 +02:00
antelle aa5a9fc6d2 Merge branch 'master' into usb
# Conflicts:
#	app/scripts/app.js
#	package.json
#	release-notes.md
2020-05-04 19:46:07 +02:00
antelle 316518d63b Merge branch 'master' into develop
# Conflicts:
#	package.json
#	release-notes.md
2020-05-04 19:45:03 +02:00
antelle 03c44d76c9 Merge branch 'release-1.14'
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
2020-05-04 19:21:54 +02:00
antelle 346d6cb119 fixed dist html file location 2020-05-04 19:21:29 +02:00
antelle dae3d57d1e Merge branch 'release-1.14' 2020-05-04 19:12:47 +02:00
antelle aa65cef103 bump version 2020-05-04 19:12:08 +02:00
antelle e19c923538 up deps 2020-05-04 19:11:20 +02:00
antelle ec292705b3 distinct redirect URIs for storage providers 2020-05-04 19:06:05 +02:00
antelle d36588d148 ignored the whole file in prettier 2020-05-02 19:54:47 +02:00
antelle 32c171d05b Merge branch 'develop' into usb 2020-05-02 14:05:47 +02:00
antelle f031be4ce2 Merge branch 'master' into develop
# Conflicts:
#	app/scripts/storage/storage-base.js
#	release-notes.md
2020-05-02 14:04:53 +02:00
antelle d3ebcabec4 Merge branch 'master' into release-1.14 2020-05-02 14:03:04 +02:00
antelle f683f14a30 up gh-actions
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
2020-05-02 13:40:03 +02:00
antelle 0a311e87e4 up gh-actions 2020-05-02 13:39:42 +02:00
antelle d42ce3e7bb npm audit 2020-05-02 13:36:09 +02:00
antelle 4c5d7eb762 Merge branch 'release-1.14' 2020-05-02 13:31:26 +02:00
antelle 1d58779d90 bump version 2020-05-02 13:30:24 +02:00
antelle 1434d81d3e bump version 2020-05-02 13:30:10 +02:00
antelle b44d060fac languages 2020-05-02 13:29:05 +02:00
antelle 7c89ebc047 fixed a typo 2020-05-01 18:37:27 +02:00
antelle d140427c94 fix #1478: fixed proxy issues with storage providers 2020-04-30 17:59:22 +02:00
antelle 2abdf3693c Merge branch 'master' into release-1.14 2020-04-30 16:33:18 +02:00
antelle 8d1eafe2bc Merge branch 'develop' into usb 2020-04-29 19:24:47 +02:00
antelle 510f982579 Merge branch 'master' into develop 2020-04-29 18:59:43 +02:00
antelle 63e6be9867 plugin ids 2020-04-29 18:48:39 +02:00
antelle 0a2957449f added blob: to script-src 2020-04-29 18:41:50 +02:00
antelle ee2ba047ab removed eval's 2020-04-29 18:41:16 +02:00
antelle a8590c1b90 icon 2020-04-29 18:17:26 +02:00
Dimitri Witkowski 374f4bc116 Create SECURITY.md 2020-04-28 23:33:23 +02:00
antelle 76fa1f6c9f merge 2020-04-23 20:50:53 +02:00
antelle dd68aa342a Merge branch 'develop' into usb
# Conflicts:
#	app/scripts/const/default-app-settings.js
#	app/scripts/views/open-view.js
2020-04-23 20:26:52 +02:00
antelle 21d614aa97 escaping dangerous places 2020-04-23 20:09:37 +02:00
antelle f4e4bbbb8f escaping dangerous places 2020-04-23 20:06:10 +02:00
antelle d30c9d9d90 escaping more dangerous places 2020-04-23 19:55:52 +02:00
antelle e0884a4eec escaping dangerous places 2020-04-23 19:24:39 +02:00
antelle 446c7f3ab5 fixed webdav pattern 2020-04-23 19:17:05 +02:00
antelle 48a6189fe7 dropdown hint option 2020-04-23 19:12:15 +02:00
antelle e568d06b02 fix #1350: clearing master password after auto lock period 2020-04-23 18:47:46 +02:00
antelle 243c962667 #1471: WebDAV url validation 2020-04-23 18:39:59 +02:00
antelle 908510ff0b fix #1342: hint that the data will be stored in unencrypted form after exporting 2020-04-23 18:36:26 +02:00
antelle d6aab0c470 fix #1463: copying the original url instead of adding https: 2020-04-23 18:30:17 +02:00
antelle 8d2640d99d fix #1400: auto-apply tag when creating new entry in tag view 2020-04-23 18:20:46 +02:00
antelle d45748cc32 fix #557, fix #513: Argon2 speed improvements in desktop apps 2020-04-23 18:12:16 +02:00
antelle 2693dd9366 more network logging
(cherry picked from commit 92fb322f7b)
2020-04-21 16:35:20 +02:00
antelle dcfa070176 translated a dropbox message
(cherry picked from commit abc154738c)
2020-04-21 16:34:22 +02:00
antelle eb577d61d5 fix 2020-04-19 20:55:38 +02:00
antelle f79bb90b69 tooling check 2020-04-19 20:42:55 +02:00
antelle 4591268063 settings 2020-04-19 18:52:21 +02:00
antelle 7e849934ff Merge branch 'develop' into usb 2020-04-19 16:11:11 +02:00
antelle 92fb322f7b more network logging 2020-04-18 15:48:47 +02:00
antelle abc154738c translated a dropbox message 2020-04-18 15:48:29 +02:00
antelle 63850f75af Merge branch 'master' into develop 2020-04-18 15:23:40 +02:00
antelle e0498e5e87 contributing 2020-04-18 13:11:05 +02:00
antelle 232f0b8d69 issue template 2020-04-18 13:08:43 +02:00
antelle d410dbb17d issue template 2020-04-18 13:06:04 +02:00
antelle e7c3d0441c issue template 2020-04-18 13:04:27 +02:00
antelle 0119d69641 readme 2020-04-18 13:00:21 +02:00
antelle a21fdf50bb contributing 2020-04-18 12:59:09 +02:00
antelle 8fdc5e6d94 contributing 2020-04-18 12:56:18 +02:00
antelle 41e81c2d7a contributing 2020-04-18 12:53:30 +02:00
antelle 10d2f5e641 contributing 2020-04-18 12:53:05 +02:00
antelle cdfcc6493c contributing 2020-04-18 12:48:57 +02:00
antelle 6b26f6d93f contributing 2020-04-18 12:48:26 +02:00
antelle a11cf38378 contributing 2020-04-18 12:47:28 +02:00
antelle 7d061c4aaf contributing 2020-04-18 12:47:00 +02:00
antelle 152fcccf60 contributing 2020-04-18 12:40:10 +02:00
antelle 159104a50a merge 2020-04-18 11:04:06 +02:00
antelle 66b2b77791 Merge branch 'develop' into usb
# Conflicts:
#	app/scripts/models/app-settings-model.js
#	desktop/app.js
2020-04-18 11:03:06 +02:00
antelle 36ade29e46 Merge branch 'master' into develop 2020-04-18 10:52:41 +02:00
antelle 61c44057cb Merge branch 'release-1.14' 2020-04-18 10:52:07 +02:00
antelle fd9dc1a801 github action rebuilt 2020-04-18 10:51:29 +02:00
antelle 57b813196f Merge branch 'release-1.14' into develop 2020-04-18 09:04:49 +02:00
antelle eaf429de3d downgraded a dependency dut to failing ci
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
2020-04-18 08:40:33 +02:00
antelle 45923d034e Merge branch 'develop' 2020-04-18 08:30:17 +02:00
antelle fbdfacd14d saving only modified settings instead of everything 2020-04-18 08:28:56 +02:00
antelle a55ddda6cf release notes 2020-04-18 08:05:57 +02:00
antelle 6c66d0791a deps 2020-04-18 08:05:12 +02:00
antelle c19d427f3a bump version 2020-04-17 23:28:21 +02:00
antelle a078081347 bump version 2020-04-17 22:25:52 +02:00
antelle 3a042f25c2 disabled navigation in desktop 2020-04-17 21:54:34 +02:00
antelle 6d781a6358 disabled creation of new windows 2020-04-17 21:50:53 +02:00
antelle 349ec59df7 option to log out from storages 2020-04-17 21:36:56 +02:00
antelle 833aa3c748 canOpenWebdav is now canOpenStorage 2020-04-17 20:58:47 +02:00
antelle eca5b1c7a0 moved CSP a bit closer to the beginning of the html 2020-04-17 20:56:23 +02:00
antelle 0aa925f95d checking origin in window message handlers 2020-04-17 20:53:40 +02:00
antelle 2f214b25c7 filtering protocols in the url field 2020-04-17 20:45:41 +02:00
antelle 38c3a46395 escaping html in dropdowns 2020-04-17 20:28:03 +02:00
antelle cbb9a29c8d escaping html in tooltips 2020-04-17 20:06:30 +02:00
antelle dddc4f235e escaping html in the notes field 2020-04-17 19:58:17 +02:00
antelle c537d0f464 using OAuth authorization code grant for all storage providers 2020-04-17 19:42:35 +02:00
antelle 8be588afdf Merge branch 'develop' into usb 2020-04-15 19:52:54 +02:00
antelle 5b6c707de5 Merge branch 'master' into develop 2020-04-15 19:52:29 +02:00
antelle 8b6dd322a7 release notes template 2020-04-15 19:51:42 +02:00
antelle dfdbd8b092 devtools fix 2020-04-15 19:37:03 +02:00
antelle 4fad58b1e9 Merge branch 'develop' into usb
# Conflicts:
#	app/scripts/models/app-settings-model.js
#	app/templates/open.hbs
2020-04-15 18:23:52 +02:00
antelle 6003b21f6a Merge branch 'master' into develop 2020-04-15 18:22:41 +02:00
antelle 963f09057c Merge branch 'release-1.13'
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
2020-04-15 17:52:15 +02:00
antelle b185c3e102 bump version 2020-04-15 17:29:56 +02:00
antelle 272365dde7 up languages 2020-04-15 17:28:51 +02:00
antelle da91254cf0 #1456: options to hide webdav and password generator 2020-04-15 17:26:10 +02:00
antelle 70642b464e fix #1457: fixed styles in theme plugins 2020-04-15 17:12:02 +02:00
antelle 035a4485b7 usb 101 2020-04-15 16:50:01 +02:00
antelle 73ac7496e2 Merge branch 'master' into develop 2020-04-11 18:29:15 +02:00
antelle 40d816f86d Merge remote-tracking branch 'remotes/origin/release-1.13'
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
2020-04-11 18:25:40 +02:00
antelle c513fb06e7 bump version 2020-04-11 18:24:46 +02:00
antelle dec0b4d171 fix #1451: fixed slow global auto-type on desktop 2020-04-11 18:24:23 +02:00
antelle 03ed25f617 Merge branch 'master' into develop 2020-04-11 17:14:59 +02:00
antelle 487afe799e up deps 2020-04-10 19:53:19 +02:00
antelle d15366ee24 copying 404 to dist 2020-04-09 18:38:27 +02:00
antelle 816c7776f7 copying 404 to dist 2020-04-09 18:36:56 +02:00
antelle f5eadc5d9e Merge branch 'release-1.13'
Build / web (push) Canceled after 0s
Build / linux (push) Canceled after 0s
Build / darwin (push) Canceled after 0s
Build / win32 (push) Canceled after 0s
Build / publish (push) Canceled after 0s
2020-04-09 07:22:35 +02:00
antelle 8e02c0bd10 bump version 2020-04-09 07:21:08 +02:00
antelle 614f61ce29 Merge branch 'develop' 2020-04-09 07:18:27 +02:00
antelle 6c80d50290 deleted GCP_SA_EMAIL 2020-04-08 23:37:21 +02:00
antelle 5492e53ba9 fix #1443: CI 2020-04-08 23:32:32 +02:00
antelle e795a317cc fixed docker build 2020-04-08 20:23:45 +02:00
antelle 8eb7366a4e finish-release task 2020-04-08 08:02:59 +02:00
antelle b85eab9d10 fix app name 2020-04-07 22:49:19 +02:00
antelle 09b0920337 release notes publishing: bin 2020-04-07 20:21:34 +02:00
antelle 502860ac5e release notes publishing 2020-04-07 20:17:56 +02:00
antelle 68d845ff3d fixed Docker build 2020-04-07 17:12:53 +02:00
antelle b2e69b60a6 files previously created as v4.1 will be written as v4.0 2020-04-07 17:07:05 +02:00
antelle 8015da09e8 debugging publish 2020-04-06 21:56:27 +02:00
antelle 06ed20f59c debugging publish 2020-04-06 21:51:54 +02:00
antelle a003d8bfe6 fixed release file path 2020-04-06 21:48:32 +02:00
antelle 468aa28449 publish release action 2020-04-06 21:41:44 +02:00
antelle e0615c751e ci 2020-04-05 23:39:36 +02:00
antelle 81e4a0eff9 ci 2020-04-05 23:29:34 +02:00
antelle b48ece91b2 ci 2020-04-05 23:21:39 +02:00
antelle 912d2b1e0a signtool 2020-04-05 22:45:46 +02:00
antelle c97f45e3e5 exlint 2020-04-05 22:15:35 +02:00
antelle de4230e0d0 code signing 2020-04-05 22:13:06 +02:00
antelle 79ca627e7c remote code signing 2020-04-05 21:43:32 +02:00
antelle 52045ad2a6 removed an old comment 2020-04-04 22:55:12 +02:00
antelle a6a9554868 Merge branch 'master' into develop 2020-04-04 22:54:23 +02:00
antelle d92229095d bump version 2020-04-04 21:53:02 +02:00
antelle 1d1ce0c322 Merge branch 'release-1.13' 2020-04-04 21:42:05 +02:00
antelle cb45eb4b3c Merge branch 'master' into release-1.13
# Conflicts:
#	Gruntfile.js
2020-04-04 21:41:29 +02:00
antelle 0b31150a43 Merge branch 'develop' 2020-04-04 21:39:40 +02:00
antelle b626152fda desktop-win32 2020-04-04 21:15:07 +02:00
antelle 3cc2cedaa5 codesign path 2020-04-04 20:27:43 +02:00
antelle e2fb54f88d desktop-darwin 2020-04-04 20:07:26 +02:00
antelle 1f334ab3dc ci 2020-04-04 19:53:18 +02:00
antelle c39933c051 fix #1447: fixed opening databases from Dock 2020-04-04 19:46:19 +02:00
antelle b6719e8972 promise 2020-04-04 19:43:12 +02:00
antelle cfaa765858 building desktop apps on ci 2020-04-04 19:26:27 +02:00
antelle 8477df7e5c build folder 2020-04-04 18:04:42 +02:00
antelle 40f3ccc112 fix deploy 2020-04-04 18:02:51 +02:00
antelle a40c116617 linux build action 2020-04-04 18:02:32 +02:00
antelle c97219311f dist name 2020-04-04 17:12:01 +02:00
antelle 49d618f066 disabled publish 2020-04-04 17:00:07 +02:00
antelle 129a77ae7c disabled publish 2020-04-04 16:36:24 +02:00
antelle b2d13db01f disabled publish 2020-04-04 16:27:19 +02:00
antelle c76cebc469 desktop-linux 2020-04-04 10:52:53 +02:00
antelle 668bb9b5d5 removed --no-sign 2020-04-04 10:25:12 +02:00
antelle ec82af7a68 fixed codesign config error 2020-04-04 10:07:10 +02:00
antelle 73b7880d73 fixed codesign config error 2020-04-04 09:55:11 +02:00
antelle a584eecb70 a developer => the developer 2020-04-03 22:47:14 +02:00
antelle cd0a25f910 fix #1445: fixed offline mode in Chrome and Firefox 2020-04-03 22:44:08 +02:00
antelle 6cf2bf109c fix #1444: fixed website favicons and attached images 2020-04-03 22:30:20 +02:00
antelle f6b7c7bb00 Merge branch 'develop' 2020-04-03 21:09:32 +02:00
antelle e987970969 languages 2020-04-03 21:08:02 +02:00
antelle 18d8037309 bump version 2020-04-03 20:28:48 +02:00
antelle 4c1dda68b5 signing code on a Windows VM 2020-04-03 20:26:27 +02:00
antelle 086f2c73db checking links being opened 2020-04-03 18:25:26 +02:00
antelle f7eab86166 removed insecure options from popups, see #1437 2020-04-03 18:17:44 +02:00
antelle 05b2b395ad preventing navigation in the main window 2020-04-03 18:06:14 +02:00
antelle c5298242f6 fixed appimage 2020-04-03 17:17:30 +02:00
antelle 37914d3cb5 allow key rotation in updated plugins 2020-04-02 16:47:50 +02:00
antelle 280ed45199 fix #1438: content security policy 2020-04-02 16:27:10 +02:00
antelle ea20740581 downgraded prettier 2020-03-31 22:00:56 +02:00
antelle 3b7d28130b up deps 2020-03-31 19:30:50 +02:00
antelle 72503916a1 svg icons 2020-03-29 15:01:11 +02:00
antelle cb150bdba9 fetching time 2020-03-29 11:11:16 +02:00
antelle 7c16a79629 fix profiling 2020-03-29 11:06:05 +02:00
antelle 1f5cd55272 app startup time profiling 2020-03-29 10:59:40 +02:00
antelle 7f4a7f05f5 displaying fetch time 2020-03-29 09:55:17 +02:00
antelle 95239fb257 start profiler 2020-03-29 09:23:49 +02:00
antelle f2583bc37f renamed the variable to KEEWEB_PORTABLE_EXECUTABLE_DIR, see #1065 2020-03-24 17:07:30 +01:00
antelle 00d7ff6604 favicon service url 2020-03-24 07:55:28 +01:00
antelle 5011c3ba04 deploy 2020-03-23 21:46:02 +01:00
antelle 9baa446675 removed tools 2020-03-23 21:33:11 +01:00
antelle 9e7f86e4d6 cloning keeweb-site from master 2020-03-23 18:36:20 +01:00
antelle 5ac4b42452 logging storage requests 2020-03-22 20:58:29 +01:00
antelle e9b05fe345 release notes 2020-03-22 07:55:16 +01:00
antelle 13ac013e9f input position 2020-03-21 17:46:39 +01:00
antelle d3b635ffd6 eslint 2020-03-21 17:39:36 +01:00
antelle e09609cc68 input width 2020-03-21 17:38:34 +01:00
antelle d2f64630f5 input width 2020-03-21 16:53:44 +01:00
antelle 0c3d8b77e4 grammar 2020-03-21 16:49:25 +01:00
antelle 905d09899c fix #1295, fix #1353: displaying passwords as protected fields regardless of settings in the file 2020-03-21 15:54:12 +01:00
antelle 0712c9f24b moved tests 2020-03-21 12:43:59 +01:00
antelle 29329f924e password presenter test 2020-03-21 12:24:21 +01:00
antelle c6c307c50c url format tests 2020-03-21 12:08:27 +01:00
antelle b96b477f65 format tests 2020-03-21 11:56:26 +01:00
antelle 4f53e39f8d md-to-html test 2020-03-21 11:45:40 +01:00
antelle 5cac16a632 string format test 2020-03-21 11:37:55 +01:00
antelle a1a02d5098 id generator test 2020-03-21 11:26:49 +01:00
antelle 72c77305e4 password generator tests 2020-03-21 11:23:19 +01:00
antelle d6980ab0b3 up deps 2020-03-20 21:05:39 +01:00
antelle 4ee0a1edaf removed an expensive check from startup 2020-03-20 18:40:43 +01:00
antelle ef7a4ff583 using pkcs11-smartcard-sign 2020-03-19 20:53:30 +01:00
antelle e8979594a1 up deps 2020-03-19 19:56:12 +01:00
antelle 690488abdd rotated the signature key 2020-03-19 19:50:44 +01:00
antelle f7910a1546 Merge pull request #1432 from canthar/maintainer
Fix: MAINTAINER directive in Dockerfile is deprecated
2020-03-19 18:56:30 +01:00
Tomasz Meresiński 42b92ec081 Fix: MAINTAINER directive in Dockerfile is deprecated 2020-03-19 18:34:10 +01:00
antelle b32684ab7b file associations for rpm 2020-03-18 19:52:17 +01:00
antelle eedc4374b9 fix #890: deb will no longer install to /opt 2020-03-17 23:09:46 +01:00
antelle 76304395bd fixed appdata package id 2020-03-17 23:05:04 +01:00
antelle d3dabc35e5 moved appdata package 2020-03-17 23:04:20 +01:00
antelle 039b45e926 renamed appdata package 2020-03-17 23:03:47 +01:00
antelle bf1b162cbc fix #855: appdata file in deb packages 2020-03-17 22:58:08 +01:00
antelle be3c7a8314 fix #784, fix #572, fix #450: more linux releases: AppImage, RPM, Snap 2020-03-17 22:46:21 +01:00
antelle 3bfa95a032 page => tab 2020-03-17 20:17:07 +01:00
antelle 5f1121a241 added a better message for the browser tab 2020-03-17 20:16:44 +01:00
antelle 7ccf38f0df fix #1359: fixed Google Drive login issues in desktop apps 2020-03-17 19:45:38 +01:00
antelle 61d83319d4 KEEWEB_OPEN_DEVTOOLS variable 2020-03-17 07:52:34 +01:00
antelle 1bc8cffbf3 cleaned up code 2020-03-15 18:44:20 +01:00
antelle a7acfb0291 eslint 2020-03-15 18:41:27 +01:00
antelle fb34f8890f #1029: fixed syncing files by timeout when there are no changes 2020-03-15 18:40:37 +01:00
antelle 3d3864d535 #615: translated shortcut modifier keys 2020-03-15 17:34:57 +01:00
antelle 3f9296e38c #411: option to automatically use group icon for new entries 2020-03-15 17:22:25 +01:00
antelle 3a17a370f2 fix #516: scrolling on the open screen on mobile 2020-03-15 17:02:39 +01:00
antelle 42833accc0 #766: setting for no/unlimited history 2020-03-15 15:54:06 +01:00
antelle 85e9a4c4c6 fix #895: generator positioning in list view 2020-03-15 15:19:50 +01:00
antelle 2c0624d5b4 fix #1142: submit button on mobile password input 2020-03-15 13:01:24 +01:00
antelle 347c8fff73 fix #1309: back button in attachment preview 2020-03-15 12:41:02 +01:00
antelle fa17aa4a57 fixed enter keypress in custom field title 2020-03-15 11:51:10 +01:00
antelle 8021c6bb81 fix #1006: password generator patterns 2020-03-15 11:20:01 +01:00
antelle c4be2e5d00 fix #1338: minimized option not working on linux 2020-03-15 10:14:00 +01:00
antelle cbd0c7b228 - fix #1378: screen orientation issues on Android PWA 2020-03-14 21:14:29 +01:00
antelle 0b13c06a09 fix #1293: copying full urls 2020-03-14 21:12:13 +01:00
antelle a5c6180154 fix #1387: fixed drag-drop for otp fields 2020-03-14 21:01:41 +01:00
antelle 19e899ba97 #1393: option to disable saving and exporting (canSaveTo) 2020-03-14 20:51:42 +01:00
antelle 3d9965c4af fix #1391: passwords imported from CSV were not hidden 2020-03-14 20:45:28 +01:00
antelle 98c22a4323 fix #1396: fixed hyperlinks in notes 2020-03-14 20:32:55 +01:00
antelle 649516cf32 removed debug code 2020-03-14 20:30:47 +01:00
antelle 29c0e840d3 up deps 2020-03-14 20:29:55 +01:00
antelle 3a5a7063cd fix #1397: using Segoe UI on Windows 2020-03-14 19:25:00 +01:00
antelle f601dbe313 proper fix #1395 2020-03-14 19:22:48 +01:00
antelle 0640009752 Merge pull request #1427 from harshlele/advanced-search-password
fix #1395 - advanced search will cause a typeerror
2020-03-13 18:05:43 +01:00
Harshal Lele f153d99744 fix #1395 - advanced search will cause a typeerror 2020-03-13 13:37:12 +05:30
antelle 85c07dba9c checking if the directory exists, see #1418 2020-03-09 16:33:28 +01:00
antelle 7ace45929a Merge pull request #1405 from loginov-rocks/patch-2
Make the app installable as PWA
2020-02-10 17:28:46 +01:00
Danila Loginov 212a7a7551 Make the app installable as PWA
In order to be installable as PWA, the app should have at least start_url property in the manifest.

To address https://github.com/keeweb/keeweb/issues/1360
2020-02-06 16:59:42 +03:00
antelle fd9f579802 package-lock.json 2020-01-19 12:28:35 +01:00
antelle ee1b451f59 moved the config a bit later 2020-01-19 12:20:19 +01:00
antelle a2873fd782 Merge pull request #1394 from bradchristensen/bugfix/build-on-windows
Add support for building KeeWeb on Windows
2020-01-19 12:19:29 +01:00
Brad Christensen fc549fe006 Update README to use npm scripts (which use --no-sign by default) 2020-01-19 23:31:32 +13:00
Brad Christensen b931e5d273 Follow the existing convention to use the provided grunt instance 2020-01-19 23:18:50 +13:00
Brad Christensen 25101b5a02 Use Grunt's built-in method of parsing command line args 2020-01-19 23:12:16 +13:00
Brad Christensen 9c32293fa8 Add --no-sign arg to toggle code signing in Grunt 2020-01-19 21:01:59 +13:00
Brad Christensen de6255b388 Fix npm script to run Electron on Windows 2020-01-18 17:21:54 +13:00
Brad Christensen 6566fbe71c Gracefully degrade if code signing config is not available 2020-01-18 17:00:25 +13:00
Brad Christensen 556fc31000 Fix build config to support Windows path separators and newlines 2020-01-18 16:42:36 +13:00
antelle 1072e5778f fix #1385: fixed a file watcher error on network locations 2020-01-05 15:45:06 +01:00
antelle 29bad845b1 Merge pull request #1377 from alex-shpak/cordova
Update cordova launcher, remove unnecessary code.
2019-12-16 22:51:34 +01:00
Alex Shpak a80061d97f Update cordova launcher, remove unnecessary code 2019-12-16 22:37:42 +01:00
antelle bc1d6ce5d8 fixed auto-type text 2019-12-06 18:29:23 +01:00
antelle c6c41d5f2d fixed password generation entropy 2019-11-13 17:00:43 +01:00
antelle 4ded2c1848 simplified generator code a bit 2019-11-13 16:59:22 +01:00
antelle df90fc9c33 Merge branch 'GrantMoyer-develop' into develop 2019-11-13 16:57:37 +01:00
Grant Moyer b1da50133b Remove "binning" from password generation 2019-11-12 20:39:08 -05:00
antelle a65d7208c7 fix #1208: webdav credentials corruption 2019-11-08 19:07:38 +01:00
antelle 36a53cc405 fix #1065: PORTABLE_EXECUTABLE_DIR environment variable 2019-11-06 23:14:20 +01:00
antelle cccb9ac681 fix #1341: auto-lock the app on screen lock on Windows 2019-11-06 23:01:05 +01:00
antelle 0a025d807b Merge branch 'master' into develop
# Conflicts:
#	release-notes.md
2019-11-06 22:59:07 +01:00
antelle 9b07bbd505 Merge branch 'release-1.12' 2019-11-06 19:54:08 +01:00
antelle f224aea444 fixed entry title input size 2019-11-06 19:53:50 +01:00
antelle e21257de0c bump version 2019-11-06 19:48:57 +01:00
antelle ecf2a65e16 fix #1334: saving new files not working 2019-11-06 19:46:17 +01:00
antelle 1f4f3101f2 fix #1335: removed the menubar on Windows and Linux 2019-11-04 21:36:14 +01:00
antelle d66b33fd19 Merge branch 'master' into develop
# Conflicts:
#	release-notes.md
2019-11-03 12:52:37 +01:00
antelle 5d5913233b Merge branch 'release-1.12' 2019-11-03 12:26:29 +01:00
antelle 2b6e8c030d bump version 2019-11-03 12:25:55 +01:00
antelle b1e0056a3a shorter notation 2019-11-03 11:31:46 +01:00
antelle d64eb95388 filtering file info properties 2019-11-03 11:31:08 +01:00
antelle 8794b0d37c fix #1337: displaying groups in trash 2019-11-03 11:24:33 +01:00
antelle beda8972e8 fix #1333: item selection in the auto-type pop-up 2019-11-03 10:04:34 +01:00
antelle c655defe6d fix #1336: saving disabled storage option 2019-11-03 10:00:46 +01:00
antelle 6dc459a64f readme links 2019-11-03 09:51:05 +01:00
antelle 90979be600 Update FUNDING.yml 2019-10-27 22:34:12 +01:00
antelle 6b1361ad9d fix #734: OTP secrets with spaces 2019-10-27 18:59:09 +01:00
antelle bede42388f fixed non-working updater 2019-10-27 16:43:47 +01:00
antelle 604c1bd3d4 Merge branch 'master' into develop
# Conflicts:
#	release-notes.md
2019-10-27 11:05:23 +01:00
antelle 149c565ee6 Merge branch 'release-1.12' 2019-10-27 10:41:42 +01:00
antelle efca3632cc bump version 2019-10-27 10:41:02 +01:00
antelle 60468b4afa fix #1313: disabled code signing for macOS dmg 2019-10-27 10:39:00 +01:00
antelle 50976b2d09 collection tests 2019-10-27 10:35:36 +01:00
antelle 0fce37cc73 fix #1324: duplicated shortcut editor in settings 2019-10-27 09:10:00 +01:00
antelle 12c7313935 fixed electron deprecations 2019-10-26 22:58:48 +02:00
antelle 5d1162bd32 fix #1323: version in the About dialog 2019-10-26 22:56:36 +02:00
antelle 6aa3a71761 Merge branch 'release-1.12' into develop 2019-10-26 21:53:22 +02:00
antelle 3e1f1e557e Merge branch 'develop' 2019-10-26 21:09:08 +02:00
antelle 0a993fb151 languages 2019-10-26 21:08:26 +02:00
antelle e4da7ee601 bump version 2019-10-26 21:05:47 +02:00
antelle d6ef6ecdd8 fix #197: mobile actions panel 2019-10-26 20:50:52 +02:00
antelle e1f242d973 fixed adding new entries on mobile 2019-10-26 19:53:20 +02:00
antelle 1f0503907e up 2019-10-26 19:45:53 +02:00
antelle a9da298dd7 fixed generator on mobile 2019-10-26 19:19:06 +02:00
antelle d3dc13d58a removed hook-rcedit 2019-10-26 14:45:59 +02:00
antelle c7eb8caf8b fix #1319: removed a storage request for invalid passwords 2019-10-26 14:43:34 +02:00
antelle 2ca5f93e8b case 2019-10-17 20:49:36 +02:00
antelle b08ff12760 fix #1310: password generator on the start screen 2019-10-17 19:52:34 +02:00
antelle c62193d1fe #1307: option to disable Markdown support 2019-10-17 19:13:11 +02:00
antelle 858a9bf93b fix #1311: better monospace fonts 2019-10-17 18:53:09 +02:00
antelle 7a22746f67 Merge branch 'master' into develop
# Conflicts:
#	release-notes.md
2019-10-16 22:49:45 +02:00
antelle 92215e8817 Merge branch 'release-1.11' 2019-10-16 22:08:23 +02:00
antelle b449def7e6 bump version 2019-10-16 22:07:43 +02:00
antelle b7f020f69c fix #1263: desktop apps crashes when argon2 is used 2019-10-16 22:07:11 +02:00
antelle be79f67510 fix #1305: WebDAV issues 2019-10-15 20:02:44 +02:00
antelle 57af428b9e Merge branch 'master' into develop
# Conflicts:
#	release-notes.md
2019-10-13 23:27:52 +02:00
antelle 2c9c8b9ab4 Merge branch 'release-1.11' 2019-10-13 23:10:24 +02:00
antelle bc4dbc7de2 bump version 2019-10-13 23:10:05 +02:00
antelle ce55ca1e0d release date 2019-10-13 23:09:46 +02:00
antelle 99bcbc288c fix #1290: generator popup positioning in custom themes 2019-10-13 13:16:57 +02:00
antelle 517134c95b fix #1300: selecting auto-type sequence items issues 2019-10-12 18:56:33 +02:00
antelle e866bac25a fix #1300: selecting auto-type sequence items issues 2019-10-12 18:55:11 +02:00
antelle 0f5b03ce64 model tests 2019-10-12 15:33:48 +02:00
antelle 4d1cbe7f62 closing browser in tests 2019-10-12 14:24:51 +02:00
antelle 69c38cbeca running tests during build 2019-10-12 14:23:19 +02:00
antelle 936de04b1e running tests during build 2019-10-12 14:22:39 +02:00
antelle b8f7a89291 tests 2019-10-12 13:24:37 +02:00
antelle 11a3995722 extracted focus manager 2019-10-12 12:26:22 +02:00
antelle eb68da635f removed an old task 2019-10-12 08:56:23 +02:00
antelle eb2de6f3f2 focus managing refactoring 2019-10-12 08:20:44 +02:00
antelle 5b118667ef Merge branch 'master' into develop
# Conflicts:
#	release-notes.md
2019-10-11 23:51:44 +02:00
antelle f346b73baa Merge branch 'master' into release-1.11 2019-10-11 23:51:03 +02:00
antelle 0fabdac9e0 fixing build 2019-10-11 23:20:32 +02:00
antelle 590035cce9 copying mac helpers 2019-10-11 23:06:36 +02:00
antelle f1d5965bb5 bump version 2019-10-11 21:11:35 +02:00
antelle 85027aa504 Merge branch 'release-1.11' 2019-10-11 21:07:12 +02:00
antelle 72b7517623 release date 2019-10-11 20:57:30 +02:00
antelle 29c3e98c05 fixed issues with some theme plugins 2019-10-11 20:56:35 +02:00
antelle fa15c56f1c Merge pull request #1299 from trickert76/make_docker_image_customizable
Make docker image customizable
2019-10-11 20:29:35 +02:00
antelle 3eca440e0c fix #1296: search in auto-type 2019-10-11 20:26:14 +02:00
Thoralf Rickert-Wendt 9679841e22 #1298 wrong path 2019-10-11 17:49:16 +02:00
Thoralf Rickert-Wendt 16612bface #1298 using url conform delimiter 2019-10-11 17:45:54 +02:00
antelle e48f12de4a Merge pull request #1297 from coliff/patch-1
remove duplicate apple-mobile-web-app-capable meta tag
2019-10-11 17:34:15 +02:00
Thoralf Rickert-Wendt 7b4953a049 #1298 add variable to define a custom configuration within docker 2019-10-11 17:33:50 +02:00
Christian Oliff 6010bf0ba9 remove duplicate apple-mobile-web-app-capable meta tag
the meta tag:
` <meta name="apple-mobile-web-app-capable" content="yes" />`
was appearing twice
2019-10-11 18:49:18 +09:00
antelle 320bc0fe06 fix #1292: macOS app notarization 2019-10-10 23:49:51 +02:00
antelle 0411fe4cfe Merge branch 'master' into develop
# Conflicts:
#	release-notes.md
2019-10-09 23:22:04 +02:00
antelle 9513a6eb80 Merge branch 'master' into release-1.11 2019-10-09 23:21:13 +02:00
Antelle dc6afb765a added a hook for rcedit while wine is not working on macOS 2019-10-09 22:54:32 +02:00
Antelle b944e36d5c Merge branch 'release-1.11' 2019-10-08 20:21:18 +02:00
Antelle 458ba2de77 bump version 2019-10-08 20:19:45 +02:00
antelle 77423ad833 fix #1288: issues when opening a file during in auto-type mode 2019-10-08 20:09:06 +02:00
antelle 3c6c929854 fix #1289: crash on Auto sorting mode 2019-10-08 19:41:08 +02:00
antelle 89a4ef2e4d keeweb-tools 2019-10-07 19:32:51 +02:00
antelle 4644dda250 #1273: using a string from locale while creating new files 2019-10-06 18:53:39 +02:00
antelle 8c124f8980 fix #480: option to launch the app minimized 2019-10-06 13:14:12 +02:00
antelle 769cf19d5c fix #862: downloading attachments on mobile 2019-10-06 12:56:44 +02:00
antelle 42f6c51393 fixed shortcut text 2019-10-06 12:39:38 +02:00
antelle 2a47afa672 better texts on the shortcuts page 2019-10-06 12:33:03 +02:00
antelle 5a8927b547 fix #565: global shortcut to open KeeWeb 2019-10-06 12:27:18 +02:00
antelle cc9e369b6f fix #963: keyboard shortcut to copy OTP in background 2019-10-06 08:48:11 +02:00
antelle 63aee0e876 fix #1108: setting for running in an iframe 2019-10-06 08:28:59 +02:00
antelle dcce37d99e fix #1273: untranslated menu items 2019-10-05 08:37:10 +02:00
antelle 39aaac2d1b Merge branch 'master' into develop 2019-10-04 21:30:44 +02:00
antelle f1a632fb52 Merge branch 'master' into release-1.11 2019-10-04 21:29:39 +02:00
antelle 37ad3fbf0b release date 2019-10-04 21:14:49 +02:00
antelle 87cb6f8262 Merge branch 'release-1.11' 2019-10-04 21:13:43 +02:00
antelle 60eee04922 fixed the opencollective image 2019-10-04 21:13:32 +02:00
antelle 3250816523 manifest update 2019-10-04 20:13:36 +02:00
antelle 7e62173f01 bump version 2019-10-04 20:10:13 +02:00
antelle 6c0124fcf2 fix #1285: issues in moving entries across files 2019-10-04 20:09:44 +02:00
antelle a361fdac9e fixed field name 2019-10-04 19:44:31 +02:00
antelle 911772510c disabled spellcheck on the search input 2019-10-04 19:26:37 +02:00
antelle d2777ba42d fixed advanced entry search 2019-10-03 19:09:22 +02:00
antelle a4b9d1e98b fix #1022: fuzzy search 2019-09-30 20:31:12 +02:00
antelle 3b8e6d7585 up handlebars.js 2019-09-30 19:36:16 +02:00
antelle 7e0565df3b Merge branch 'master' into develop 2019-09-30 19:33:21 +02:00
antelle e8e2b49993 Merge branch 'release-1.11' 2019-09-29 23:26:32 +02:00
antelle a72aea3190 bump version 2019-09-29 23:26:07 +02:00
antelle e97572cfab fix #1279: error opening files with saved keyfiles 2019-09-29 23:25:53 +02:00
antelle 3a0ba29e25 Merge branch 'release-1.11' 2019-09-29 15:45:50 +02:00
antelle f699ece732 bump version 2019-09-29 15:45:27 +02:00
antelle 8bfa1fadda fix #1278: entry selection auto-type window issues 2019-09-29 15:43:17 +02:00
antelle 511fccd084 fix #1277: auto-type window matching on Linux 2019-09-29 15:31:02 +02:00
antelle db091b2b39 readme 2019-09-29 14:37:10 +02:00
antelle fd51fdddb3 fixed displaying errors on the plugins page 2019-09-29 12:35:47 +02:00
antelle bece4a44f1 Merge branch 'release-1.11' 2019-09-29 11:57:49 +02:00
antelle be5dcba4c6 fix #1276: release notes 2019-09-29 11:49:23 +02:00
antelle ae975cdc2f fixed GDrive connection issues 2019-09-29 11:32:03 +02:00
antelle 890097885a bump version 2019-09-29 10:38:58 +02:00
antelle 9a8f595514 fix #1275: starting the app after closing on macOS 2019-09-29 10:34:47 +02:00
antelle 113db1c97d Merge branch 'master' into release-1.11 2019-09-29 10:17:03 +02:00
antelle 11f2355099 fixed eventlisteners leak 2019-09-29 10:06:47 +02:00
antelle a275a895cb Merge branch 'release-1.11' 2019-09-29 10:01:20 +02:00
antelle f84a5a2b51 bump version 2019-09-29 10:00:31 +02:00
antelle 3c0444d812 fixed plugin search filtering 2019-09-29 09:58:45 +02:00
antelle 1c744d8d6b fixed Dropbox connection on iOS 13 homescreen 2019-09-29 09:54:52 +02:00
antelle 82cad800c2 eslint 2019-09-28 23:42:21 +02:00
antelle b6be4375bd fix #1271: loading custom plugins from config 2019-09-28 23:40:17 +02:00
antelle b635281428 Merge branch 'master' into release-1.11 2019-09-28 22:59:18 +02:00
antelle 326b9658fd fix #1271: loading custom plugins from config 2019-09-28 22:47:00 +02:00
antelle d0cc9b54f4 Merge branch 'release-1.11' 2019-09-28 22:32:09 +02:00
antelle 92dec8a7aa bump version 2019-09-28 22:30:42 +02:00
antelle 3e987cc2dc fix #1270: password change control focus 2019-09-28 22:30:21 +02:00
antelle 20843dd1fb Merge branch 'release-1.11' into develop 2019-09-28 20:56:19 +02:00
antelle 29f014abc3 fixed desktop build 2019-09-28 20:27:39 +02:00
antelle 49b5b3d41e fixed desktop apps startup 2019-09-28 20:03:03 +02:00
antelle efb0c39d33 up 2019-09-28 19:36:57 +02:00
antelle 10460f270d Merge branch 'develop' 2019-09-28 19:34:08 +02:00
antelle 0eafc4ac88 bump version 2019-09-28 19:33:27 +02:00
antelle bfc6d4b3c0 field options fix 2019-09-28 19:30:13 +02:00
antelle 9626eb904e fixed trash 2019-09-28 19:26:09 +02:00
antelle c9f62c3f3a fix otp 2019-09-28 19:22:44 +02:00
antelle be52cf86b5 file-changed event 2019-09-28 19:18:24 +02:00
antelle 922c8f2100 languages 2019-09-28 15:50:43 +02:00
antelle 7dbac45670 fixed comments in output 2019-09-28 15:49:04 +02:00
antelle 0dd4fa666a moved a lib 2019-09-28 15:44:46 +02:00
antelle 94aa1665ab release notes 2019-09-28 15:24:26 +02:00
antelle 009d854622 appmodel for keewebhttp 2019-09-28 15:20:29 +02:00
antelle 886d452996 prettier 2019-09-28 14:55:36 +02:00
antelle 0afed3f9aa comment 2019-09-28 14:52:54 +02:00
antelle e42b28ae9e fixed settings shortcuts editor 2019-09-28 14:49:49 +02:00
antelle 0672180233 fixed prop deletion 2019-09-28 14:45:47 +02:00
antelle 0cd401c45d fix #1252: public key rotation 2019-09-28 14:40:46 +02:00
antelle 2913a0421d using one key for everything 2019-09-28 14:17:55 +02:00
antelle 42134b4888 fix a color flash on start 2019-09-28 13:43:30 +02:00
antelle 8b2df9e1c8 about 2019-09-28 13:37:52 +02:00
antelle adb1fd421a fixed details on mobile 2019-09-28 13:31:52 +02:00
antelle f1173c496a plugins for Edge 2019-09-28 13:20:51 +02:00
antelle 59aebd3666 fixed copypaste 2019-09-28 12:25:07 +02:00
antelle 85b89a2d80 fixed layout issues on the import screen 2019-09-28 10:18:00 +02:00
antelle 17dedb6b8e obfuscating displayed password values 2019-09-27 07:37:26 +02:00
antelle 8fb8a9d096 #1125: field actions: copy, reveal, auto-type 2019-09-26 23:43:07 +02:00
antelle 26d0cbf2b2 group selector in csv import 2019-09-26 07:19:20 +02:00
antelle bcee01cdd1 CSV import. fix #498, fix #453 2019-09-25 23:24:38 +02:00
antelle 8060ba6453 fixed the beta build 2019-09-25 22:51:15 +02:00
antelle 62f723ff6f fix #564: Steam OTP support 2019-09-25 22:48:32 +02:00
antelle 86b5113c46 fixed method case 2019-09-25 22:47:44 +02:00
antelle e9fbd49864 Merge branch 'monroe-dylan-m-develop' into develop 2019-09-25 22:46:03 +02:00
Dylan Monroe 9c765ced45 De-linted 2019-09-25 16:25:52 -04:00
Dylan Monroe 4405fdb5fe Fixed typo 2019-09-25 16:04:25 -04:00
Dylan Monroe 645d904954 Removed duplicate assignment 2019-09-25 15:54:39 -04:00
Dylan Monroe b8be888f05 Added Steam TOTP output format 2019-09-25 15:54:10 -04:00
antelle 6aca16c336 prettified service worker 2019-09-23 20:36:54 +02:00
antelle a01d85411c fix #156: using ServiceWorker instead of AppCache 2019-09-23 20:32:56 +02:00
antelle b280c6f723 fixed authHeight property name 2019-09-22 22:30:03 +02:00
antelle f74e2bcc7f symbol name 2019-09-22 22:24:45 +02:00
antelle ae2d54f454 fixed a memory leak 2019-09-22 22:24:19 +02:00
antelle 63be5932be isequal fix 2019-09-22 22:14:45 +02:00
antelle 1565c26823 simple CSV parser 2019-09-22 18:57:18 +02:00
antelle ae72b55a2e fix #336: moving entries across files 2019-09-22 09:56:48 +02:00
antelle b83e2519ac fixed menu resize 2019-09-21 07:41:33 +02:00
antelle 22f5e61978 events in electron 2019-09-21 07:39:03 +02:00
antelle 966097e1ff up 2019-09-20 23:39:12 +02:00
antelle 0c2de37cf8 autoprefixer 2019-09-20 23:37:17 +02:00
antelle 328bdd68e2 bugfixes 2019-09-20 23:25:43 +02:00
antelle a10ee6c9f2 fix 2019-09-20 23:12:02 +02:00
antelle 383847d3aa woff2 2019-09-20 23:03:25 +02:00
antelle 2b8dca7748 added some ids 2019-09-20 22:57:36 +02:00
antelle 9a19339ec5 bugfixes 2019-09-20 22:26:32 +02:00
antelle 2f07c87801 better way of rendering collections 2019-09-20 22:20:53 +02:00
antelle c14567311b fixed file list 2019-09-20 22:18:23 +02:00
antelle bc8aad5062 fix #1256: error during updating the app 2019-09-20 20:35:05 +02:00
antelle a1a649cd9f electron events 2019-09-20 20:31:19 +02:00
antelle ba0586d407 bugfixes 2019-09-20 06:30:04 +02:00
antelle c2212ac4ad Merge branch 'master' into develop
# Conflicts:
#	package.json
#	release-notes.md
2019-09-20 06:01:44 +02:00
antelle 4548829595 release date 2019-09-20 05:58:20 +02:00
antelle 07177222a0 fixed argon2 2019-09-20 05:43:22 +02:00
antelle 723c39de85 up packages 2019-09-19 23:16:18 +02:00
antelle a20dab859f Merge branch 'release-1.10' 2019-09-19 23:06:41 +02:00
antelle acf3bc945c bump version 2019-09-19 23:06:10 +02:00
antelle 379ea9c208 languages 2019-09-19 23:05:44 +02:00
antelle 74f282a69d updated argon2 2019-09-19 23:04:18 +02:00
antelle ef7ae9ada9 Revert "fix #1154: relative Destination header in WebDAV MOVE"
This reverts commit cbbf5f83

fix #1259
2019-09-19 23:01:51 +02:00
antelle 64bf07c71e collection toJSON 2019-09-19 22:07:14 +02:00
antelle 8e30d99e94 at 2019-09-19 18:28:55 +02:00
antelle 0367966ae6 bugfixes 2019-09-19 17:42:53 +02:00
antelle 4d7cef70d2 menu models 2019-09-18 23:37:57 +02:00
antelle 2f93e53716 storage 2019-09-18 21:26:43 +02:00
antelle ebfdff90c7 plugins 2019-09-18 21:15:48 +02:00
antelle 3a5d6bc2ca button padding 2019-09-18 20:43:01 +02:00
antelle 15518a4ce0 removed underscore, added lodash 2019-09-18 20:42:17 +02:00
antelle c41bd1a4ef terser 2019-09-18 19:59:39 +02:00
antelle 9b1335720b less underscore 2019-09-18 07:12:06 +02:00
antelle 731994c9fe less underscore 2019-09-18 07:08:23 +02:00
antelle 3341f3e7f6 less underscore 2019-09-17 23:48:31 +02:00
antelle 08d7261488 less underscore 2019-09-17 23:44:17 +02:00
antelle 89ccb99395 less underscore 2019-09-17 22:17:40 +02:00
antelle 94660d9e71 updater model 2019-09-17 21:56:58 +02:00
antelle 8f4932610c runtime-data model 2019-09-17 21:50:46 +02:00
antelle b405ca970c file model 2019-09-17 21:39:06 +02:00
antelle 05b12c2d59 attachment model 2019-09-17 20:08:58 +02:00
antelle 268dfee75d app model 2019-09-17 19:58:39 +02:00
antelle 9c3c9d28fa app setting model 2019-09-17 19:50:42 +02:00
antelle 00291da933 models and collections 2019-09-17 19:01:24 +02:00
antelle 87eb0468a6 events 2019-09-17 19:01:12 +02:00
antelle f2fe249560 fix 2019-09-16 23:36:22 +02:00
antelle 42e70c1d05 key handler 2019-09-16 23:32:05 +02:00
antelle 19fa54f9d0 otp qr reader 2019-09-16 23:27:31 +02:00
antelle ec6a6e08ff fix 2019-09-16 23:19:54 +02:00
antelle 39e683baf0 cleanup 2019-09-16 23:10:22 +02:00
antelle 2fcc6f2ea3 events 2019-09-16 22:57:56 +02:00
antelle 7f30350873 readme 2019-09-16 22:03:03 +02:00
antelle 9859e921d2 exports 2019-09-16 22:01:59 +02:00
antelle 0dea89c0de event listeners 2019-09-16 21:49:21 +02:00
antelle 1aa29237e2 Merge branch 'views' into develop 2019-09-16 21:08:20 +02:00
antelle 727887fb79 bugfixes 2019-09-16 21:07:39 +02:00
antelle 12079f6ac6 bugfixes 2019-09-16 20:54:14 +02:00
antelle f1d9b5c645 moved views 2019-09-16 20:42:33 +02:00
antelle 75b4ed05ab settings views 2019-09-16 20:40:20 +02:00
antelle a2f938b0a0 removed some readme paragraphs 2019-09-16 20:12:18 +02:00
antelle 8869a27ac9 field views 2019-09-16 19:55:06 +02:00
antelle 927278317e fixed list clicks 2019-09-16 19:26:31 +02:00
antelle ccace95a6c details view 2019-09-16 19:24:15 +02:00
antelle 813ed6d541 linter fix 2019-09-16 19:10:14 +02:00
antelle e7d13ff254 details views 2019-09-16 19:09:57 +02:00
antelle b16dd74492 details views 2019-09-16 18:41:06 +02:00
antelle 2bcaa1926a jsconfig for vscode 2019-09-16 18:34:58 +02:00
antelle 1a48270a28 fake config for IDE's 2019-09-16 18:18:51 +02:00
antelle 6606fa8108 fix 2019-09-16 17:58:44 +02:00
antelle 7730486f30 move views 2019-09-16 17:43:57 +02:00
antelle ad0963e412 key change view 2019-09-16 07:13:56 +02:00
antelle 5ae07b721a dropdown view 2019-09-16 07:06:55 +02:00
antelle a695b35eca fix 2019-09-16 06:56:39 +02:00
antelle 2ce1d01535 storage-file-list view 2019-09-15 23:41:00 +02:00
antelle f8f8a7c1d1 open-config view 2019-09-15 23:24:53 +02:00
antelle 6277a48419 modal view 2019-09-15 23:18:09 +02:00
antelle 155eb493bf list-wrap view 2019-09-15 23:08:36 +02:00
antelle de2443eb5a auto-type-select view 2019-09-15 23:02:51 +02:00
antelle c9ac7f2fa3 drag view 2019-09-15 21:22:23 +02:00
antelle 22d1b478f9 auto-type-hint-view 2019-09-15 20:17:08 +02:00
antelle 43b11277ad icon select view 2019-09-15 20:09:28 +02:00
antelle 7589a112d0 view refactoring 2019-09-15 18:33:45 +02:00
antelle 9bbea458c6 imports 2019-09-15 14:16:32 +02:00
antelle 556c5dd56a moved phonetic export 2019-09-15 13:30:38 +02:00
antelle 2688e761ba moved PluginManager 2019-09-15 13:29:20 +02:00
antelle 5a10dc1f2f removed unnecessary exports 2019-09-15 13:27:24 +02:00
antelle 9c1de2aca9 moved storage modules 2019-09-15 13:24:53 +02:00
antelle c83dff46a7 renamed the mixin 2019-09-15 12:41:38 +02:00
antelle 3bae948218 grammar 2019-09-15 12:40:25 +02:00
antelle 6551622e07 fixed an error message 2019-09-15 12:37:11 +02:00
antelle 3319478876 updated browserslist 2019-09-15 12:18:21 +02:00
antelle 58b8ed7940 renamed mixins to view-engine 2019-09-15 12:14:53 +02:00
antelle bc808889a1 removed some view methods 2019-09-15 12:12:00 +02:00
antelle 5cd19cee56 protected-value-ex 2019-09-15 12:09:18 +02:00
antelle f82791096d renamed helpers 2019-09-15 08:51:24 +02:00
antelle 58726de491 path fix 2019-09-15 08:49:41 +02:00
antelle 60dcfbb071 organized files inside comp 2019-09-15 08:47:57 +02:00
antelle 9e7a86a1db organized files inside util 2019-09-15 08:11:11 +02:00
antelle 0028f2293f checking if devtools are supported before adding a shortcut 2019-09-15 07:47:45 +02:00
antelle e7d88cce58 fix #1141: opening file from storage if cache is not available 2019-09-15 07:44:04 +02:00
antelle 73635e2784 fix plugin gallery layout on mobile 2019-09-14 23:35:10 +02:00
antelle 92d4a40228 about 2019-09-14 22:32:35 +02:00
antelle 0b8bc1afb0 fixed a warning in XHR.send 2019-09-14 22:21:21 +02:00
antelle 27d86d8185 webpack fix 2019-09-14 22:14:44 +02:00
antelle dbc73a73e2 fix #713: markdown notes 2019-09-14 22:12:02 +02:00
antelle f7ef9a7b4a wording 2019-09-14 17:09:35 +02:00
antelle b06cb26edc fix #743: copying entry fields to clipboard 2019-09-14 17:06:38 +02:00
antelle 56d84e1d18 fix #348: configurable system-wide shortcuts 2019-09-14 16:36:30 +02:00
antelle 3859beb543 devtools are now opened with alt-cmd-I 2019-09-14 14:07:56 +02:00
antelle 1b2f83ea80 fix #502: increased the default value of encryption rounds 2019-09-14 13:47:47 +02:00
antelle ba122e786c fix #1255: file format version and kdf selection in settings 2019-09-14 09:34:23 +02:00
antelle cdedcd9dac babel preset-env 2019-09-13 23:25:57 +02:00
antelle 2214356d27 es6 2019-09-13 20:34:52 +02:00
antelle 02b7266206 updated windows helper for #554 2019-09-12 23:37:31 +02:00
antelle e0291b2d52 fix #554: checking active window id during auto-type 2019-09-12 22:38:21 +02:00
antelle 068e49c53c checking modal before closing the dropdown 2019-09-12 20:21:49 +02:00
antelle 0fe67c9e4a Revert "fix #1154: relative Destination header in WebDAV MOVE"
This reverts commit cbbf5f83

fix #1259
2019-09-12 20:09:45 +02:00
antelle 79dd95facd fix #1243: auto-type any field 2019-09-12 19:59:35 +02:00
antelle 9e5d6403fa fixed auto-type select view on macos theme 2019-09-12 07:12:52 +02:00
antelle 0a9296c6c4 fix #107: multiline custom fields support 2019-09-11 23:50:18 +02:00
antelle 07df05304e fix multi-line fields display in history 2019-09-11 23:04:28 +02:00
antelle 5d0556debc fix #1226: 7-digit Authy OTP support 2019-09-11 22:41:00 +02:00
antelle 789103a2b8 fix #764: multiple attachments display 2019-09-11 22:25:33 +02:00
antelle f48713409b spacing fix 2019-09-09 22:10:29 +02:00
antelle 8ecae7e745 Merge branch 'master' into develop 2019-09-09 17:30:03 +02:00
antelle 1b64dd6d56 fix build 2019-09-09 17:13:28 +02:00
antelle d4c255e240 Merge branch 'develop' 2019-09-09 17:10:44 +02:00
antelle 09894d1c8f set version 2019-09-09 17:09:42 +02:00
antelle 574fa84f7d fix set-version 2019-09-09 17:08:31 +02:00
antelle 0953a29b4e prettier 2019-09-09 17:07:24 +02:00
antelle e82732c8c0 up languages 2019-09-09 17:06:29 +02:00
antelle e2588e81f8 bump version 2019-09-09 17:03:39 +02:00
antelle c525d1f9e0 padding 2019-09-09 17:01:47 +02:00
antelle b21b9cd24e fix 2019-09-09 16:56:32 +02:00
antelle 31b0097afb fixed links 2019-09-09 16:54:14 +02:00
antelle e6aef150ee fix #1244: deb file permissions issue 2019-09-09 16:24:45 +02:00
antelle aa0d3d329e Merge branch 'master' into develop 2019-09-09 08:34:26 +02:00
antelle a9ae7ad815 removed stale bot config 2019-09-09 08:33:57 +02:00
antelle 65ba766b0f mobile fixes 2019-09-08 21:21:20 +02:00
antelle bd37cb2c26 field order 2019-09-08 20:29:07 +02:00
antelle 5703dceb0c HTML export 2019-09-08 20:28:02 +02:00
antelle 15b170db5d pretty-printing exported XML files 2019-09-08 18:09:13 +02:00
antelle ef71035e0d fixed tip size 2019-09-08 15:29:02 +02:00
antelle 7977bbf6e1 smooth window startup color transition for the dark theme 2019-09-08 15:11:41 +02:00
antelle a7f769d4f6 new screenshot 2019-09-08 15:07:34 +02:00
antelle a634d824d0 fixed calendar styles 2019-09-08 14:59:08 +02:00
antelle 42f0cc307f grammar 2019-09-08 14:39:06 +02:00
antelle 68e5955d09 mac colors 2019-09-08 14:38:26 +02:00
antelle 3df178a026 confirmation for deleting an entry on mobile 2019-09-08 14:20:11 +02:00
antelle ba57bf9503 updated the demo file 2019-09-08 14:14:07 +02:00
antelle c216d785aa displaying websites as HTTPS if no scheme is provided 2019-09-08 14:11:33 +02:00
antelle f4359fef92 fixed field editing issues 2019-09-08 14:10:35 +02:00
antelle 13f90d7a39 up bourbon 2019-09-08 13:43:55 +02:00
antelle 135c4dc60e grammar 2019-09-08 13:13:30 +02:00
antelle a78c63b05b style adjustments 2019-09-08 13:10:01 +02:00
antelle e3081cba17 changed the icon of automatic search 2019-09-08 12:59:45 +02:00
antelle bfbfaf559a fixed the button position 2019-09-08 12:54:29 +02:00
antelle 6e03932e6d show the macOS theme only on Apple devices 2019-09-08 12:53:05 +02:00
antelle c5f2bd4aa3 fix generator 2019-09-08 11:50:26 +02:00
antelle ba56444a6e fixed paddings 2019-09-08 11:46:03 +02:00
antelle 56fbc14893 picker 2019-09-08 11:32:31 +02:00
antelle 7f20e6cc46 mobile fix 2019-09-08 11:05:38 +02:00
antelle 6dba3f9bf7 macos dark theme 2019-09-08 10:54:18 +02:00
antelle 47b2c32031 bg 2019-09-08 09:56:41 +02:00
antelle 7a3281bd23 up argon2-browser 2019-09-08 09:55:46 +02:00
antelle 55f4ff8f73 eslint 2019-09-08 09:39:30 +02:00
antelle c5d8732031 up deps 2019-09-08 09:38:31 +02:00
antelle 2181c9aa91 dropped support for browsers without css variables 2019-09-08 09:31:25 +02:00
antelle 82f841fdf9 macOS dark theme 2019-09-08 09:12:15 +02:00
antelle bebb9a88eb fixed field editing styles 2019-09-08 08:25:15 +02:00
antelle 8df70602c0 Merge branch 'master' into develop 2019-09-07 21:16:57 +02:00
antelle ef39b5c79c donation link changed 2019-09-07 21:15:20 +02:00
antelle a77dd32d20 donation link 2019-09-07 21:06:33 +02:00
antelle c4dc65761c Merge branch 'open-collective' 2019-09-07 20:55:06 +02:00
antelle bc6d3fba55 removed paypal 2019-09-07 20:34:25 +02:00
antelle 1cf5171526 removed paypal 2019-09-07 20:33:46 +02:00
antelle db850ece85 wording 2019-09-07 20:29:49 +02:00
antelle be3acbe13a funding 2019-09-07 20:23:50 +02:00
antelle 670fc425ac link 2019-09-07 20:23:04 +02:00
antelle 83bd89fe50 opencollective button 2019-09-07 20:21:32 +02:00
antelle c4489d1ea0 npm audit fix 2019-09-07 19:31:25 +02:00
antelle 82a11aaf4f Merge branch 'release-1.9' 2019-09-07 19:29:41 +02:00
antelle 04a513556b bump version 2019-09-07 19:28:59 +02:00
antelle d670deb0cb Merge branch 'master' into release-1.9 2019-09-07 19:24:48 +02:00
antelle cc089b2bd1 release notes 2019-09-07 19:23:14 +02:00
antelle e812218919 fix titlebar color on macOS dark theme 2019-09-07 19:22:45 +02:00
antelle 35b531dad0 release notes 2019-09-07 19:21:48 +02:00
antelle 6715c614ac fix titlebar color on macOS dark theme 2019-09-07 19:16:09 +02:00
antelle 1a7975072f Merge branch 'master' into develop 2019-09-05 22:34:56 +02:00
antelle 2dc9959ca4 fixed menu padding issues in some browsers 2019-09-05 22:30:04 +02:00
antelle a69a5a5472 Stale bot config 2019-09-02 07:34:31 +02:00
antelle b689c96870 xml files can be now opened as regular files 2019-08-25 12:46:53 +02:00
antelle ea00818573 fix #1129: webdav storage error on Unicode filenames 2019-08-24 07:47:13 +02:00
antelle cbbf5f833a fix #1154: relative Destination header in WebDAV MOVE 2019-08-24 07:37:08 +02:00
antelle 8a258998dd fixed group settings not being displayed 2019-08-24 07:14:29 +02:00
antelle 80c44c4c03 fixed group settings not being displayed 2019-08-24 07:09:53 +02:00
antelle ba122bd9d0 fix #1241: config option to disable xml export (canExportXml) 2019-08-24 06:56:25 +02:00
antelle 58709c33a0 added a forgotten comma 2019-08-22 22:49:55 +02:00
antelle 087b1937de Merge branch 'master' into release-1.9 2019-08-22 22:42:02 +02:00
antelle 54430cd83d Merge branch 'develop' 2019-08-22 22:26:25 +02:00
antelle a35817c379 up languages 2019-08-22 22:25:59 +02:00
antelle 9375f5c281 bump version 2019-08-22 22:23:38 +02:00
antelle ba29687865 fix #1234 auto-type issues in xubuntu/xfce 2019-08-22 22:15:04 +02:00
antelle c5c64bee20 fix #1235: custom themes loading 2019-08-20 20:18:16 +02:00
antelle 74e9bb5fc7 Merge branch 'master' into develop 2019-08-19 23:34:39 +02:00
antelle e6556ca92d 2019 2019-08-19 23:33:52 +02:00
antelle 9737272e19 Create FUNDING.yml 2019-08-19 23:17:05 +02:00
antelle f5b4a2a887 Merge branch 'master' into release-1.9 2019-08-19 21:04:10 +02:00
antelle d16f335627 up de 2019-08-19 21:03:33 +02:00
antelle 46adf5dcc1 version 2019-08-19 20:59:54 +02:00
antelle 2c38f3c8f2 fix #1234: auto-type not working on linux 2019-08-19 20:55:25 +02:00
antelle 105205661f fix #1232: removed an unwanted menubar on windows and linux 2019-08-19 20:10:58 +02:00
antelle a69cf5cd85 improved ranking search 2019-08-18 16:14:47 +02:00
antelle 7c5b76fda3 fix #1231: tooltip arrow positioning 2019-08-18 14:44:51 +02:00
antelle 7e2d531533 Merge branch 'release-1.9' into develop 2019-08-18 11:39:12 +02:00
antelle 64c41785f6 removed linux-ia32 2019-08-18 11:24:25 +02:00
antelle 69a3dd14ba removed old lib 2019-08-18 11:21:24 +02:00
antelle 2a4ed6f264 removed support for linux/ia32
See more details here: https://electronjs.org/blog/linux-32bit-support
2019-08-18 11:17:00 +02:00
antelle ba2d9415be version 2019-08-18 11:10:27 +02:00
antelle 60dfb3c21f Merge branch 'develop' 2019-08-18 11:08:42 +02:00
antelle 9816ab5c80 eslintrc 2019-08-18 10:18:18 +02:00
antelle 904a1e12d2 release notes 2019-08-18 10:17:54 +02:00
antelle f8395f7f38 better eslint 2019-08-18 10:17:09 +02:00
antelle 0df1ba97d5 min electron version 2019-08-18 08:19:39 +02:00
antelle d581cb13af release notes 2019-08-18 08:18:36 +02:00
antelle ede597d67e comma 2019-08-18 08:17:32 +02:00
antelle fe7078aebf version 2019-08-18 08:16:10 +02:00
antelle 2f855d5c8a deleted old file 2019-08-18 08:15:46 +02:00
antelle 6788b77f32 year 2019-08-18 08:12:11 +02:00
antelle 2bb4584235 prettier path 2019-08-18 08:10:45 +02:00
antelle 3e3d3571be eslint 2019-08-18 08:09:42 +02:00
antelle fa4ff0b0c3 prettier 2019-08-18 08:05:38 +02:00
antelle 176c2a6edd moved the loader 2019-08-18 07:58:23 +02:00
antelle 74a005d0e3 removed an unused field 2019-08-17 20:09:24 +02:00
antelle 02bb56357f better error description 2019-08-17 19:30:42 +02:00
antelle d9ad69b085 readme 2019-08-17 17:59:24 +02:00
antelle 824b0d3e3c readme 2019-08-17 17:58:00 +02:00
antelle 8ab1ec615f bugfixes for new Electron and webpack 2019-08-17 15:20:00 +02:00
antelle 5fb3228841 release notes 2019-08-17 13:36:30 +02:00
antelle 0e4538650d fix #1171: enabled updater on Linux 2019-08-17 13:36:03 +02:00
antelle 012bc61f4a fixed electron script 2019-08-17 13:17:54 +02:00
antelle 0d126ae0d8 fix #1166: prevent webdav password logging 2019-08-17 11:39:22 +02:00
antelle 2c064989c1 fix #1215: url matching when there's no website field 2019-08-17 11:28:45 +02:00
antelle 51cc550502 fix #1209: copying app information to clipboard 2019-08-17 11:15:23 +02:00
antelle e2e7176b51 readme 2019-08-17 10:51:46 +02:00
antelle de784bd95c readme 2019-08-17 10:48:16 +02:00
antelle 854e627065 fixed editorconfig 2019-08-16 23:09:14 +02:00
antelle 84a23e4aea prettier 2019-08-16 23:05:39 +02:00
antelle 68245629e4 fixed argon2 2019-08-16 22:30:03 +02:00
antelle fd0a8287dc fix fonts 2019-08-16 22:04:29 +02:00
antelle ebd0578ea2 up deps 2019-08-16 21:51:50 +02:00
antelle e1b0409648 up deps 2019-08-16 21:50:23 +02:00
antelle 17a777b7e6 readme 2019-08-16 21:36:30 +02:00
antelle 336c80e296 up eslint 2019-08-16 21:36:22 +02:00
antelle fcd8a99924 ignored .iml 2019-08-16 20:03:58 +02:00
antelle a7096b5cdf building css with webpack 2019-08-16 18:45:11 +02:00
antelle 32b4e99c12 merge GrantMoyer-develop: option to hide password in the generator 2019-08-15 22:08:26 +02:00
antelle c2658395c0 fixed generator style issues in Firefox, see #1222 2019-08-15 21:25:02 +02:00
antelle d3935a49de up node-sass 2019-08-15 21:25:02 +02:00
Grant Moyer 4892e7aa2b Only create a hidden input if not simpleCopy 2019-08-14 23:20:03 -04:00
Grant Moyer d96f458a1b Easy requested changes 2019-08-14 22:59:53 -04:00
Grant Moyer 93b05e448e Remove hide button from copy mode of password generator
Also fix a regression I had introduced
2019-08-07 19:49:27 -04:00
antelle 63f68dff04 fixed generator style issues in Firefox, see #1222 2019-08-07 20:32:38 +02:00
antelle 7d0760469a up node-sass 2019-08-07 20:30:00 +02:00
Grant Moyer 065ca2dad4 Remove extraneous change and fix indentation 2019-08-06 22:25:57 -04:00
Grant Moyer 03f566e7cd Fix copying hidden password 2019-08-06 20:07:55 -04:00
Grant Moyer 9c8ebde19d Move hide button to top of dialog 2019-08-06 18:48:21 -04:00
Grant Moyer ebcbe6496a Add tooltip to password hiding button 2019-08-05 22:24:26 -04:00
Grant Moyer a2a5d6d10a Remove existing tooltip when creating a new one 2019-08-05 22:23:54 -04:00
Grant Moyer 276afa42da Add option to hide generated password 2019-08-05 19:22:29 -04:00
antelle 2437ae575c fix #1221: added '30 min' lock option 2019-08-05 18:47:01 +02:00
antelle ce5b0cb303 copy the cookies file if it's not possible to move it 2019-04-25 18:17:37 +02:00
antelle 1357c7cb1c fixed a phrase 2019-04-23 19:06:05 +02:00
antelle 2c334f4346 fixed a phrase 2019-04-23 19:05:41 +02:00
antelle 0a7c0f64d2 Merge branch 'master' into develop 2019-04-22 11:47:41 +02:00
emyarod 9427d2191a bump kdbxweb version 2019-04-22 11:43:29 +02:00
antelle 8096353e6e bump version 2019-04-22 11:43:29 +02:00
antelle 3f400a8b2a fix #1163: fixed libgconf-2-4 dependency 2019-04-22 11:43:29 +02:00
antelle 3ddefff1df merge emyarod/1161-bump-kdbxweb-version develop 2019-04-20 09:30:30 +02:00
emyarod ddd5370f69 bump kdbxweb version 2019-04-15 13:17:05 -07:00
antelle 6f203f0a3e removed obsolete code 2019-04-13 11:04:31 +02:00
antelle c795784417 Merge branch 'master' into develop 2019-04-05 20:49:31 +02:00
antelle c115ba79c8 Merge branch 'release-1.8' 2019-04-05 20:27:04 +02:00
antelle 47eb538444 Merge pull request #1153 from dploeger/fix-1152
Fixed missing preparation for filter on autotype
2019-04-04 19:16:25 +02:00
Dennis Ploeger fa136af90a bug: Fixed missing preparation for filter on autotype 2019-04-02 14:09:12 +02:00
Dennis Ploeger 1ab397be0a bug: Fixed missing preparation for filter on autotype 2019-04-02 14:08:56 +02:00
806 changed files with 83495 additions and 38706 deletions
+20
View File
@@ -0,0 +1,20 @@
{
"presets": [
["@babel/typescript", { "jsxPragma": "h" }]
],
"plugins": [
["@babel/transform-react-jsx", {
"runtime": "automatic",
"importSource": "preact"
}],
["@babel/plugin-proposal-class-properties", { "loose": true }],
["@babel/plugin-proposal-object-rest-spread", { "loose": true,
"useBuiltIns": true
}],
"@babel/plugin-proposal-optional-catch-binding",
"@babel/plugin-proposal-optional-chaining",
"@babel/plugin-proposal-nullish-coalescing-operator",
"@babel/plugin-proposal-logical-assignment-operators",
"@babel/plugin-external-helpers"
]
}
+1 -13
View File
@@ -15,17 +15,5 @@ trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
[*.json]
indent_size = 2
[.eslintrc]
indent_size = 4
[*.scss]
indent_size = 2
[*.css]
indent_size = 2
[*.nsh]
[{*.nsh,*.yml,*.yaml,*.json}]
indent_size = 2
-39
View File
@@ -1,39 +0,0 @@
{
"extends": "standard",
"rules": {
"indent": ["error", 4, { "SwitchCase": 1 }],
"semi": ["error", "always"],
"one-var": "off",
"space-before-function-paren": "off",
"no-throw-literal": "off",
"camelcase": ["error", { "properties": "always" }],
"no-console": "error",
"no-alert": "error",
"no-debugger": "error",
"prefer-arrow-callback": "error",
"object-property-newline": "off",
"no-useless-escape": "off",
"no-var": "error",
"prefer-const": "error",
"no-unused-expressions": "error",
"strict": ["error", "never"],
"no-mixed-operators": "off",
"prefer-promise-reject-errors": "off",
"standard/no-callback-literal": "off",
"import/no-webpack-loader-syntax": "off",
"object-curly-spacing": "off"
},
"parserOptions": {
"sourceType": "module",
"ecmaFeatures": {
"impliedStrict": true
}
},
"globals": {
"_": true,
"$": true
},
"env": {
"browser": true
}
}
+243
View File
@@ -0,0 +1,243 @@
{
"plugins": [
"prettier",
"import",
"babel",
"react",
"@typescript-eslint"
],
"extends": [
"standard",
"eslint:recommended",
"plugin:prettier/recommended"
],
"rules": {
"semi": [
"error",
"always"
],
"one-var": "off",
"space-before-function-paren": "off",
"no-throw-literal": "off",
"camelcase": [
"error",
{
"properties": "always"
}
],
"no-console": "error",
"no-alert": "error",
"no-debugger": "error",
"prefer-arrow-callback": "error",
"object-property-newline": "off",
"no-useless-escape": "off",
"no-var": "error",
"prefer-const": "error",
"no-unused-expressions": "off",
"strict": [
"error",
"never"
],
"no-mixed-operators": "off",
"prefer-promise-reject-errors": "off",
"standard/no-callback-literal": "off",
"object-curly-spacing": "off",
"quote-props": "off",
"no-new-object": "error",
"object-shorthand": "error",
"no-array-constructor": "error",
"array-callback-return": "error",
"no-eval": "error",
"no-new-func": "error",
"prefer-rest-params": "error",
"prefer-spread": "error",
"no-useless-constructor": "error",
"no-dupe-class-members": "error",
"no-duplicate-imports": "error",
"eqeqeq": "error",
"no-unneeded-ternary": "error",
"curly": "error",
"prettier/prettier": "error",
"no-empty": "off",
"no-restricted-syntax": [
"error",
{
"selector": "ExportDefaultDeclaration",
"message": "Prefer named exports"
}
],
"import/no-webpack-loader-syntax": "off",
"import/no-relative-parent-imports": "error",
"import/first": "error",
"import/no-default-export": "error",
"babel/no-unused-expressions": "error",
"node/no-callback-literal": "off"
},
"parserOptions": {
"sourceType": "module",
"ecmaFeatures": {
"impliedStrict": true
}
},
"parser": "babel-eslint",
"overrides": [
{
"files": [
"*.ts",
"*.tsx"
],
"extends": [
"standard",
"eslint:recommended",
"preact",
"plugin:prettier/recommended",
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking",
"plugin:import/typescript"
],
"rules": {
"semi": [
"error",
"always"
],
"one-var": "off",
"space-before-function-paren": "off",
"no-throw-literal": "error",
"camelcase": [
"error",
{
"properties": "always"
}
],
"no-console": "error",
"no-alert": "error",
"no-debugger": "error",
"prefer-arrow-callback": "error",
"object-property-newline": "off",
"no-useless-escape": "off",
"no-var": "error",
"prefer-const": "error",
"no-unused-expressions": "off",
"strict": [
"error",
"never"
],
"no-mixed-operators": "off",
"prefer-promise-reject-errors": "off",
"standard/no-callback-literal": "off",
"object-curly-spacing": "off",
"quote-props": "off",
"no-new-object": "error",
"object-shorthand": "error",
"no-array-constructor": "error",
"array-callback-return": "error",
"no-eval": "error",
"no-new-func": "error",
"prefer-rest-params": "error",
"prefer-spread": "error",
"no-useless-constructor": "error",
"no-dupe-class-members": "off",
"no-duplicate-imports": "error",
"eqeqeq": "error",
"no-unneeded-ternary": "error",
"curly": "error",
"prettier/prettier": "error",
"no-empty": "off",
"no-restricted-syntax": [
"error",
{
"selector": "ExportDefaultDeclaration",
"message": "Prefer named exports"
}
],
"import/no-webpack-loader-syntax": "off",
"import/no-relative-parent-imports": "error",
"import/first": "error",
"import/no-default-export": "error",
"babel/no-unused-expressions": "error",
"node/no-callback-literal": "off",
"import/no-commonjs": "off",
"prefer-template": "off",
"no-else-return": "off",
"jest/valid-expect": "off",
"jest/expect-expect": "off",
"react-hooks/exhaustive-deps": "off",
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/explicit-module-boundary-types": "error",
"@typescript-eslint/no-non-null-assertion": "error",
"@typescript-eslint/no-var-requires": "off",
"@typescript-eslint/naming-convention": [
"error",
{
"selector": ["objectLiteralProperty", "classProperty", "typeProperty"],
"modifiers": ["private", "protected"],
"format": ["camelCase"],
"leadingUnderscore": "require",
"trailingUnderscore": "forbid"
},
{
"selector": ["classProperty", "typeProperty"],
"modifiers": ["public"],
"format": ["camelCase", "PascalCase", "UPPER_CASE", "snake_case"],
"leadingUnderscore": "forbid",
"trailingUnderscore": "forbid"
},
{
"selector": ["method"],
"format": ["camelCase"],
"leadingUnderscore": "forbid",
"trailingUnderscore": "forbid"
},
{
"selector": ["class", "enum"],
"format": ["PascalCase"],
"leadingUnderscore": "forbid",
"trailingUnderscore": "forbid"
},
{
"selector": ["enumMember"],
"format": ["PascalCase", "UPPER_CASE"],
"leadingUnderscore": "forbid",
"trailingUnderscore": "forbid"
},
{
"selector": ["variable"],
"format": ["camelCase", "PascalCase", "UPPER_CASE"],
"leadingUnderscore": "forbid",
"trailingUnderscore": "forbid"
}
]
},
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 11,
"sourceType": "module",
"project": [
"tsconfig.json",
"jsconfig.json"
]
}
}
],
"settings": {
"import/parsers": {
"@typescript-eslint/parser": [
".ts",
".tsx"
]
}
},
"globals": {
"_": true,
"$": true
},
"env": {
"browser": true,
"node": true,
"es2020": true
}
}
+12
View File
@@ -0,0 +1,12 @@
# These are supported funding model platforms
github: [keeweb, antelle]
patreon: # Replace with a single Patreon username
open_collective: keeweb
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # for example PayPal links
+2 -2
View File
@@ -2,7 +2,7 @@
name: Bug report
about: Create a report to help us improve KeeWeb
title: ''
labels: ''
labels: 'bug'
assignees: ''
---
@@ -24,7 +24,7 @@ A clear and concise description of what you expected to happen.
If applicable, add screenshots to help explain your problem.
**Environment**
Your user-agent (from Settings/Help section)
Please copy all version information from Settings/Help
**Kdbx File**
Does it happen on Demo or New database?
+1
View File
@@ -0,0 +1 @@
blank_issues_enabled: true
+1 -1
View File
@@ -2,7 +2,7 @@
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
labels: 'enhancement'
assignees: ''
---
+11
View File
@@ -0,0 +1,11 @@
FROM snapcore/snapcraft:stable
COPY entrypoint.sh /entrypoint.sh
RUN apt-get update
RUN apt-get install -y build-essential git-core unzip curl pkg-config rpm
RUN curl -sL https://deb.nodesource.com/setup_15.x | sudo -E bash -
RUN apt-get install -y nodejs
RUN npm i -g grunt-cli
ENTRYPOINT ["/entrypoint.sh"]
+5
View File
@@ -0,0 +1,5 @@
name: 'Linux Build'
description: 'Build KeeWeb on Linux in Docker'
runs:
using: 'docker'
image: 'Dockerfile'
+5
View File
@@ -0,0 +1,5 @@
#!/bin/bash -e
cd /github/workspace
npm ci
grunt desktop-linux
+404
View File
@@ -0,0 +1,404 @@
#!/usr/bin/env python3
#
# git-restore-mtime - Change mtime of files based on commit date of last change
#
# Copyright (C) 2012 Rodrigo Silva (MestreLion) <linux@rodrigosilva.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. See <http://www.gnu.org/licenses/gpl.html>
#
"""
Change the modification time (mtime) of all files in work tree, based on the
date of the most recent commit that modified the file.
Useful prior to generating release tarballs, so each file is archived with a
date that is similar to the date when the file was actually last modified,
assuming the actual modification date and its commit date are close.
By default ignores all ignored and untracked files, and also refuses to work
on trees with uncommitted changes.
"""
# TODO:
# - Add -z on git whatchanged/ls-files so we don't deal with filename decode/OS normalization
# - When Python is bumped to 3.7, use text instead of universal_newlines on subprocess
# - Update "Statistics for some large projects" with modern hardware and repositories.
# - Create a README.md for git-restore-mtime alone. It deserves extensive documentation
# - Move Statistics there
# FIXME:
# - When current dir is outside the worktree, e.g. using --work-tree, `git ls-files`
# assume any relative pathspecs are to worktree root, not the current dir. As such,
# relative pathspecs may not work.
# - Renames and mode changes should not change file mtime:
# - Must check on status 'R100' and mode changes with same blobs
# - Should require status to be (A, C, M, R<100, T). D will never be processed as
# filelist is a subset of lsfileslist.
# - Check file (A, D) for directory mtime is not sufficient:
# - Renames also change dir mtime, unless rename was on a parent dir
# - If most recent change of all files in a dir was a [M]odification,
# dir might not be touched at all.
# - Dirs containing only subdirectories but no direct files will also
# not be touched. They're files' [grand]parent dir, but never their dirname().
# - Some solutions:
# - After files done, perform some dir processing for missing dirs, finding latest
# file (A, D, R)
# - Simple approach: dir mtime is most recent child (dir or file) mtime
# - Use a virtual concept of "created at most at" to fill missing info, bubble up
# to parents and grandparents
# - When handling [grand]parent dirs, stay inside <pathspec>
# - Better handling of merge commits. `-m` is plain *wrong*. `-c/--cc` is perfect, but
# painfully slow. First pass without merge commits is not accurate. Maybe add a new
# `--accurate` mode for `--cc`?
if __name__ != "__main__":
raise ImportError("{} should not be used as a module.".format(__name__))
import subprocess, shlex
import sys, os.path
import logging
import argparse
import time
# Update symlinks only if the OS supports not following them
UPDATE_SYMLINKS = bool(os.utime in getattr(os, 'supports_follow_symlinks', []))
STEPMISSING = 100
# Command-line interface ######################################################
def parse_args():
parser = argparse.ArgumentParser(
description="""Restore original modification time of files based on the date of the
most recent commit that modified them. Useful when generating release tarballs.""")
group = parser.add_mutually_exclusive_group()
group.add_argument('--quiet', '-q', dest='loglevel',
action="store_const", const=logging.WARNING, default=logging.INFO,
help="Suppress informative messages and summary statistics.")
group.add_argument('--verbose', '-v', action="count",
help="Print additional information for each processed file.")
parser.add_argument('--force', '-f', action="store_true",
help="Force execution on trees with uncommitted changes.")
parser.add_argument('--merge', '-m', action="store_true",
help="""Include merge commits. Leads to more recent mtimes and more files per
commit, thus with the same mtime (which may or may not be what you want). Including
merge commits may lead to less commits being evaluated (all files are found sooner),
which improves performance, sometimes substantially. But since merge commits are
usually huge, processing them may also take longer, sometimes substantially.
By default merge logs are only used for files missing from regular commit logs.""")
parser.add_argument('--first-parent', action="store_true",
help="""Consider only the first parent, the "main branch", when parsing merge
commit logs. Only effective when merge commits are included in the log, either
by --merge or to find missing files after first log parse. See --skip-missing.""")
parser.add_argument('--skip-missing', '-s',
action="store_false", default=True, dest="missing",
help="""Do not try to find missing files. If some files were not found in regular
commit logs, by default it re-tries using merge commit logs for these files (if
--merge was not already used). This option disables this behavior, which may slightly
improve performance, but files found only in merge commits will not be updated.""")
parser.add_argument('--no-directories', '-D',
action="store_false", default=True, dest='dirs',
help="""Do not update directory mtime for files created, renamed or deleted in it.
Note: just modifying a file will not update its directory mtime.""")
parser.add_argument('--test', '-t', action="store_true", default=False,
help="Test run: do not actually update any file")
parser.add_argument('--commit-time', '-c',
action='store_true', default=False, dest='commit_time',
help="Use commit time instead of author time")
parser.add_argument('pathspec', nargs='*', metavar='PATH',
help="""Only modify paths matching PATH, directories or files, relative to current
directory. Default is to modify all files handled by git, ignoring untracked files
and submodules.""")
parser.add_argument('--work-tree', dest='workdir',
help="Path to the work tree, if not current directory or one of its parents.")
parser.add_argument('--git-dir', dest='gitdir',
help="Path to the git repository, if not the default <work-tree-root>/.git")
parser.add_argument('--skip-older-than', metavar='SECONDS', type=int,
help="""Do not modify files that are older than %(metavar)s.
It can significantly improve performance if fewer files are processed.
Useful on CI builds, which can eventually switch workspace to different branch,
but mostly performs builds on the same one (e.g. master).
""")
return parser.parse_args()
# Helper functions ############################################################
def setup_logging(args):
TRACE = logging.DEBUG // 2
logging.Logger.trace = lambda _, m, *a, **k: _.log(TRACE, m, *a, **k)
level = (args.verbose and max(TRACE, logging.DEBUG // args.verbose)) or args.loglevel
logging.basicConfig(level=level, format='%(message)s')
return logging.getLogger()
def normalize(path):
"""Normalize paths from git, handling non-ASCII characters.
Git for Windows, as of v1.7.10, stores paths as UTF-8 normalization form C. If path
contains non-ASCII or non-printable chars it outputs the UTF-8 in octal-escaped
notation, double-quoting the whole path. Double-quotes and backslashes are also escaped.
https://git-scm.com/docs/git-config#Documentation/git-config.txt-corequotePath
https://github.com/msysgit/msysgit/wiki/Git-for-Windows-Unicode-Support
https://github.com/git/git/blob/master/Documentation/i18n.txt
Example on git output, this function reverts this:
r'back\slash_double"quote_açaí' -> r'"back\\slash_double\"quote_a\303\247a\303\255"'
"""
if path and path[0] == '"':
# Python 2: path = path[1:-1].decode("string-escape")
# Python 3: https://stackoverflow.com/a/46650050/624066
path = (path[1:-1] # Remove enclosing double quotes
.encode('latin1') # Convert to bytes, required 'unicode-escape'
.decode('unicode-escape') # Perform the actual octal-escaping decode
.encode('latin1') # 1:1 mapping to bytes, forming UTF-8 encoding
.decode('utf8')) # Decode from UTF-8
# Make sure the slash matches the OS; for Windows we need a backslash
return os.path.normpath(path)
if UPDATE_SYMLINKS:
def touch(path, mtime, test=False):
"""The actual mtime update"""
if test: return
os.utime(path, (mtime, mtime), follow_symlinks=False)
else:
def touch(path, mtime, test=False):
"""The actual mtime update"""
if test: return
os.utime(path, (mtime, mtime))
def isodate(secs):
return time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(secs))
# Git class and parselog(), the heart of the script ###########################
class Git():
def __init__(self, workdir=None, gitdir=None):
self.gitcmd = ['git']
if workdir: self.gitcmd.extend(('--work-tree', workdir))
if gitdir : self.gitcmd.extend(('--git-dir', gitdir))
self.workdir, self.gitdir = self._repodirs()
def ls_files(self, pathlist=None):
return (normalize(_) for _ in self._run('ls-files --full-name', pathlist))
def is_dirty(self):
return bool(self._run('diff --no-ext-diff --quiet', output=False))
def log(self, merge=False, first_parent=False, commit_time=False, pathlist=None):
cmd = 'whatchanged --pretty={}'.format('%ct' if commit_time else '%at')
if merge: cmd += ' -m'
if first_parent: cmd += ' --first-parent'
return self._run(cmd, pathlist)
def _repodirs(self):
return (os.path.normpath(_) for _ in
self._run('rev-parse --show-toplevel --absolute-git-dir', check=True))
def _run(self, cmdstr, pathlist=None, output=True, check=False):
cmdlist = self.gitcmd + shlex.split(cmdstr)
if pathlist:
cmdlist.append('--')
cmdlist.extend(pathlist)
log.trace("Executing: %s", ' '.join(cmdlist))
if not output:
return subprocess.call(cmdlist)
if check:
try:
stdout = subprocess.check_output(cmdlist, universal_newlines=True)
return stdout.splitlines()
except subprocess.CalledProcessError as e:
raise self.Error(e.returncode, e.cmd, e.output, e.stderr)
self.proc = subprocess.Popen(cmdlist, stdout=subprocess.PIPE, universal_newlines=True)
return (_.strip() for _ in self.proc.stdout)
class Error(subprocess.CalledProcessError): pass
def parselog(filelist, dirlist, stats, git, merge=False, filterlist=None):
mtime = 0
for line in git.log(merge, args.first_parent, args.commit_time, filterlist):
stats['loglines'] += 1
# Blank line between Date and list of files
if not line: continue
# File line
if line[0] == ':': # Faster than line.startswith(':')
# If line describes a rename, linetok has three tokens, otherwise two
linetok = line.split('\t')
status = linetok[0]
file = linetok[-1]
# Handles non-ASCII chars and OS path separator
file = normalize(file)
if file in filelist:
stats['files'] -= 1
log.debug("%d\t%d\t%d\t%s\t%s",
stats['loglines'], stats['commits'], stats['files'],
isodate(mtime), file)
filelist.remove(file)
try:
touch(os.path.join(git.workdir, file), mtime, args.test)
stats['touches'] += 1
except Exception as e:
log.error("ERROR: %s", e)
stats['errors'] += 1
if args.dirs:
dirname = os.path.dirname(file)
if status[-1] in ('A', 'D') and dirname in dirlist:
log.debug("%d\t%d\t-\t%s\t%s",
stats['loglines'], stats['commits'],
isodate(mtime), "{}/".format(dirname or '.'))
dirlist.remove(dirname)
try:
touch(os.path.join(git.workdir, dirname), mtime, args.test)
stats['dirtouches'] += 1
except Exception as e:
log.error("ERROR: %s", e)
stats['direrrors'] += 1
# Date line
else:
stats['commits'] += 1
mtime = int(line)
# All files done?
if not stats['files']:
git.proc.terminate() # hackish, but does the job. Not needed anyway
return
# Main Logic ##################################################################
def main():
start = time.time() # yes, Wall time. CPU time is not realistic for users.
stats = {_: 0 for _ in ('loglines', 'commits', 'touches', 'errors', 'dirtouches', 'direrrors')}
# First things first: Where and Who are we?
try:
git = Git(args.workdir, args.gitdir)
except Git.Error as e:
# Not in a git repository, and git already informed user on stderr. So we just...
return e.returncode
# Do not work on dirty repositories, unless --force
if not args.force and git.is_dirty():
log.critical(
"ERROR: There are local changes in the working directory.\n"
"This could lead to undesirable results for modified files.\n"
"Please, commit your changes (or use --force) and try again.\n"
"Aborting")
return 1
# Get the files managed by git and build file and dir list to be processed
filelist = set()
dirlist = set()
if UPDATE_SYMLINKS and not args.skip_older_than:
filelist = set(git.ls_files(args.pathspec))
dirlist = set(os.path.dirname(_) for _ in filelist)
else:
for path in git.ls_files(args.pathspec):
fullpath = os.path.join(git.workdir, path)
# Symlink (to file, to dir or broken - git handles the same way)
if not UPDATE_SYMLINKS and os.path.islink(fullpath):
log.warning("WARNING: Skipping symlink, OS does not support update: %s", path)
continue
# skip files which are older than given threshold
if args.skip_older_than and start - os.path.getmtime(fullpath) > args.skip_older_than:
continue
# Always add them relative to worktree root
filelist.add(path)
dirlist.add(os.path.dirname(path))
stats['totalfiles'] = stats['files'] = len(filelist)
log.info("{0:,} files to be processed in work dir".format(stats['totalfiles']))
if not filelist:
# Nothing to do. Exit silently and without errors, just like git does
return
# Process the log until all files are 'touched'
log.debug("Line #\tLog #\tF.Left\tModification Time\tFile Name")
parselog(filelist, dirlist, stats, git, args.merge, args.pathspec)
# Missing files
if filelist:
# Try to find them in merge logs, if not done already
# (usually HUGE, thus MUCH slower!)
if args.missing and not args.merge:
filterlist = list(filelist)
for i in range(0, len(filterlist), STEPMISSING):
parselog(filelist, dirlist, stats, git,
merge=True, filterlist=filterlist[i:i+STEPMISSING])
# Still missing some?
for file in filelist:
log.warning("WARNING: not found in log: %s", file)
# Final statistics
# Suggestion: use git-log --before=mtime to brag about skipped log entries
log.info(
"Statistics:\n"
"{:13,.2f} seconds\n"
"{:13,} log lines processed\n"
"{:13,} commits evaluated"
"".format(time.time()-start, stats['loglines'], stats['commits']))
if args.dirs:
if stats['direrrors']: log.info("{:13,} directory update errors".format(stats['direrrors']))
log.info("{:13,} directories updated".format(stats['dirtouches']))
if stats['touches'] != stats['totalfiles']: log.info("{:13,} files".format(stats['totalfiles']))
if stats['files']: log.info("{:13,} files missing".format(stats['files']))
if stats['errors']: log.info("{:13,} file update errors".format(stats['errors']))
log.info("{:13,} files updated".format(stats['touches']))
if args.test:
log.info("TEST RUN - No files modified!")
args = parse_args()
log = setup_logging(args)
log.trace("Arguments: %s", args)
# UI done, it's show time!
try:
sys.exit(main())
except KeyboardInterrupt:
log.info("Aborting")
sys.exit(-1)
+424
View File
@@ -0,0 +1,424 @@
name: Build
on:
push:
tags: [ '*' ]
jobs:
web:
runs-on: ubuntu-latest
steps:
- name: Get current git tag
id: get_tag
uses: keeweb/get-git-tag@v3.0.2
with:
tagRegex: "^v(\\d+\\.\\d+\\.\\d+)$"
tagRegexGroup: 1
- name: Checkout
uses: actions/checkout@v2
with:
repository: keeweb/keeweb
ref: ${{ github.repository == 'keeweb/keeweb' && github.sha || 'develop' }}
- name: Upgrade Node.js
uses: actions/setup-node@v2
with:
node-version: '16'
registry-url: 'https://registry.npmjs.org'
- name: Install npm modules
run: npm ci
- name: Lint
run: npm lint
- name: Test
run: npm test
- name: Build
run: npm start
- name: Upload artifact
uses: actions/upload-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.html
path: dist
- name: Write secrets
env:
VIRUS_TOTAL: ${{ secrets.VIRUS_TOTAL }}
run: |
mkdir keys
echo "$VIRUS_TOTAL" > keys/virus-total.json
- name: Check on VirusTotal
run: npm start virustotal
if: ${{ github.repository == 'keeweb/keeweb' }}
linux:
runs-on: ubuntu-latest
needs:
- web
steps:
- name: Get current git tag
id: get_tag
uses: keeweb/get-git-tag@v3.0.2
with:
tagRegex: "^v(\\d+\\.\\d+\\.\\d+)$"
tagRegexGroup: 1
- name: Checkout
uses: actions/checkout@v2
with:
repository: keeweb/keeweb
ref: ${{ github.repository == 'keeweb/keeweb' && github.sha || 'develop' }}
- name: Download artifact
uses: actions/download-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.html
path: dist
- name: Write secrets
env:
PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
KEEWEB_SIGN: ${{ secrets.KEEWEB_SIGN }}
run: |
mkdir keys
echo "$PRIVATE_KEY" > keys/private-key.pem
echo "$KEEWEB_SIGN" > keys/keeweb-sign.json
- name: Build in Docker
uses: ./.github/actions/linux-build
- name: Upload AppImage artifact
uses: actions/upload-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.AppImage
path: dist/desktop/KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.AppImage
- name: Upload snap artifact
uses: actions/upload-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.snap
path: dist/desktop/KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.snap
- name: Upload deb artifact
uses: actions/upload-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.x64.deb
path: dist/desktop/KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.x64.deb
- name: Upload zip artifact
uses: actions/upload-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.x64.zip
path: dist/desktop/KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.x64.zip
- name: Upload rpm artifact
uses: actions/upload-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.x86_64.rpm
path: dist/desktop/KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.x86_64.rpm
darwin:
runs-on: macos-latest
needs:
- web
steps:
- name: Get current git tag
id: get_tag
uses: keeweb/get-git-tag@v3.0.2
with:
tagRegex: "^v(\\d+\\.\\d+\\.\\d+)$"
tagRegexGroup: 1
- name: Checkout
uses: actions/checkout@v2
with:
repository: keeweb/keeweb
ref: ${{ github.repository == 'keeweb/keeweb' && github.sha || 'develop' }}
- name: Download artifact
uses: actions/download-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.html
path: dist
- name: Upgrade Node.js
uses: actions/setup-node@v2
with:
node-version: '16'
registry-url: 'https://registry.npmjs.org'
- name: Install npm modules
run: npm ci
- name: Write secrets
env:
CODESIGN: ${{ secrets.CODESIGN }}
APPLE_DEPLOY_PASSWORD: ${{ secrets.APPLE_DEPLOY_PASSWORD }}
APPLE_ID_USERNAME: ${{ secrets.APPLE_ID_USERNAME }}
APPLE_PROVISIONING_PROFILE: ${{ secrets.APPLE_PROVISIONING_PROFILE }}
run: |
mkdir keys
echo "$CODESIGN" > keys/codesign.json
xcrun altool --store-password-in-keychain-item "AC_PASSWORD" -u "$APPLE_ID_USERNAME" -p "$APPLE_DEPLOY_PASSWORD"
echo "$APPLE_PROVISIONING_PROFILE" | base64 -d > keys/keeweb.provisionprofile
- name: Import certificates
uses: keeweb/import-codesign-certs@v1
with:
p12-file-base64: ${{ secrets.APPLE_CERTIFICATE }}
p12-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
- name: Build
run: npm start -- --max-old-space-size=4096 desktop-darwin ${{ github.repository != 'keeweb/keeweb' && '--skip-sign' || '' }}
- name: Upload x64 dmg artifact
uses: actions/upload-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.mac.x64.dmg
path: dist/desktop/KeeWeb-${{ steps.get_tag.outputs.tag }}.mac.x64.dmg
- name: Upload arm64 dmg artifact
uses: actions/upload-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.mac.arm64.dmg
path: dist/desktop/KeeWeb-${{ steps.get_tag.outputs.tag }}.mac.arm64.dmg
win32:
runs-on: windows-latest
needs:
- web
steps:
- name: Get current git tag
id: get_tag
uses: keeweb/get-git-tag@v3.0.2
with:
tagRegex: "^v(\\d+\\.\\d+\\.\\d+)$"
tagRegexGroup: 1
- name: Checkout
uses: actions/checkout@v2
with:
repository: keeweb/keeweb
ref: ${{ github.repository == 'keeweb/keeweb' && github.sha || 'develop' }}
- name: Download artifact
uses: actions/download-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.html
path: dist
- name: Upgrade Node.js
uses: actions/setup-node@v2
with:
node-version: '16'
registry-url: 'https://registry.npmjs.org'
- name: Install npm modules
run: npm ci
- name: Write secrets
env:
CODESIGN: ${{ secrets.CODESIGN }}
MS_CODESIGN_PRIVATE_KEY_CLIENT: ${{ secrets.MS_CODESIGN_PRIVATE_KEY_CLIENT }}
MS_CODESIGN_PUBLIC_KEY_CLIENT: ${{ secrets.MS_CODESIGN_PUBLIC_KEY_CLIENT }}
MS_CODESIGN_PUBLIC_KEY_SERVER: ${{ secrets.MS_CODESIGN_PUBLIC_KEY_SERVER }}
run: |
mkdir keys
echo $Env:CODESIGN > keys/codesign.json
mkdir keys/code-signing
echo $Env:MS_CODESIGN_PRIVATE_KEY_CLIENT > keys/code-signing/private-key-client.pem
echo $Env:MS_CODESIGN_PUBLIC_KEY_CLIENT > keys/code-signing/public-key-client.pem
echo $Env:MS_CODESIGN_PUBLIC_KEY_SERVER > keys/code-signing/public-key-server.pem
- name: Build
run: npm start -- desktop-win32 ${{ github.repository != 'keeweb/keeweb' && '--skip-sign' || '' }}
- name: Upload ia32 exe artifact
uses: actions/upload-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.win.ia32.exe
path: dist/desktop/KeeWeb-${{ steps.get_tag.outputs.tag }}.win.ia32.exe
- name: Upload ia32 zip artifact
uses: actions/upload-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.win.ia32.zip
path: dist/desktop/KeeWeb-${{ steps.get_tag.outputs.tag }}.win.ia32.zip
- name: Upload x64 exe artifact
uses: actions/upload-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.win.x64.exe
path: dist/desktop/KeeWeb-${{ steps.get_tag.outputs.tag }}.win.x64.exe
- name: Upload x64 zip artifact
uses: actions/upload-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.win.x64.zip
path: dist/desktop/KeeWeb-${{ steps.get_tag.outputs.tag }}.win.x64.zip
- name: Upload arm64 exe artifact
uses: actions/upload-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.win.arm64.exe
path: dist/desktop/KeeWeb-${{ steps.get_tag.outputs.tag }}.win.arm64.exe
- name: Upload arm64 zip artifact
uses: actions/upload-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.win.arm64.zip
path: dist/desktop/KeeWeb-${{ steps.get_tag.outputs.tag }}.win.arm64.zip
publish:
runs-on: ubuntu-latest
needs:
- linux
- darwin
- win32
steps:
- name: Get current git tag
id: get_tag
uses: keeweb/get-git-tag@v3.0.2
with:
tagRegex: "^v(\\d+\\.\\d+\\.\\d+)$"
tagRegexGroup: 1
- name: Setup GCloud
uses: google-github-actions/setup-gcloud@master
with:
version: '285.0.0'
service_account_key: ${{ secrets.GCP_SA_KEY }}
export_default_credentials: true
- name: Checkout
uses: actions/checkout@v2
with:
repository: keeweb/keeweb
path: keeweb
ref: ${{ github.repository == 'keeweb/keeweb' && github.sha || 'develop' }}
- name: Upgrade Node.js
uses: actions/setup-node@v2
with:
node-version: '16'
registry-url: 'https://registry.npmjs.org'
- name: Install npm modules
working-directory: keeweb
run: npm ci
- name: Download html artifact
uses: actions/download-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.html
path: html
- name: Download linux.AppImage artifact
uses: actions/download-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.AppImage
path: assets
- name: Download linux.snap artifact
uses: actions/download-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.snap
path: assets
- name: Download linux.deb artifact
uses: actions/download-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.x64.deb
path: assets
- name: Download linux.zip artifact
uses: actions/download-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.x64.zip
path: assets
- name: Download linux.rpm artifact
uses: actions/download-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.x86_64.rpm
path: assets
- name: Download darwin.x64.dmg artifact
uses: actions/download-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.mac.x64.dmg
path: assets
- name: Download darwin.arm64.dmg artifact
uses: actions/download-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.mac.arm64.dmg
path: assets
- name: Download win32.ia32.exe artifact
uses: actions/download-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.win.ia32.exe
path: assets
- name: Download win32.ia32.zip artifact
uses: actions/download-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.win.ia32.zip
path: assets
- name: Download win32.x64.exe artifact
uses: actions/download-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.win.x64.exe
path: assets
- name: Download win32.x64.zip artifact
uses: actions/download-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.win.x64.zip
path: assets
- name: Download win32.arm64.exe artifact
uses: actions/download-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.win.arm64.exe
path: assets
- name: Download win32.arm64.zip artifact
uses: actions/download-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.win.arm64.zip
path: assets
- name: Zip html
working-directory: html
run: zip -vr ../assets/KeeWeb-${{ steps.get_tag.outputs.tag }}.html.zip .
- name: Copy assets to dist
run: mkdir -p keeweb/dist/desktop && cp assets/* keeweb/dist/desktop
- name: Write secrets
env:
PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
KEEWEB_SIGN: ${{ secrets.KEEWEB_SIGN }}
working-directory: keeweb
run: |
mkdir keys
echo "$PRIVATE_KEY" > keys/private-key.pem
echo "$KEEWEB_SIGN" > keys/keeweb-sign.json
- name: Build
working-directory: keeweb
run: npm start finish-release
- name: Copy signatures to assets
run: cp keeweb/dist/desktop/Verify.sign.sha256 assets
- name: Copy checksums to assets
run: cp keeweb/dist/desktop/Verify.sha256 assets
- name: Login to DockerHub Registry
env:
DOCKERHUB_ACCESS_TOKEN: ${{ secrets.DOCKERHUB_ACCESS_TOKEN }}
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
run: echo $DOCKERHUB_ACCESS_TOKEN | docker login -u $DOCKERHUB_USERNAME --password-stdin
- name: Copy dist to the Docker context
run: cp -r html keeweb/package/docker/dist
- name: Build the Docker image
working-directory: keeweb
run: docker build -t antelle/keeweb:latest -t antelle/keeweb:${{ steps.get_tag.outputs.tag }} package/docker
- name: Push the Docker image to dockerhub
if: ${{ github.repository == 'keeweb/keeweb' }}
run: docker push --all-tags antelle/keeweb
- name: Extract release notes
run: node util/extract-release-notes.js --version=${{ steps.get_tag.outputs.tag }} --output=tmp/release-body.md
working-directory: keeweb
- name: Publish GitHub release
uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: v${{ steps.get_tag.outputs.tag }}
name: Desktop apps v${{ steps.get_tag.outputs.tag }}
files: assets/*
body_path: keeweb/tmp/release-body.md
- name: Checkout gh-pages
uses: actions/checkout@v2
with:
ref: gh-pages
path: gh-pages
fetch-depth: 0
- name: Commit dist to gh-pages
working-directory: gh-pages
run: |
git rm -r '*'
cp -r ../html/* .
mkdir -p .github/workflows
echo $GITHUB_SHA > build.txt
date >> build.txt
git add .
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git commit -am v${{ steps.get_tag.outputs.tag }}
- name: Push gh-pages
uses: keeweb/github-push-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: gh-pages
directory: gh-pages
- name: Restore git mtime
working-directory: gh-pages
run: python3 ../keeweb/.github/actions/scripts/git-restore-mtime.py
- name: Sync the website
if: ${{ github.repository == 'keeweb/keeweb' }}
run: gsutil -m rsync -r -d -x "^\." gh-pages gs://app.keeweb.info/
- name: Purge CloudFlare cache
if: ${{ github.repository == 'keeweb/keeweb' }}
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
run: |
curl -sS -X POST "https://api.cloudflare.com/client/v4/zones/dbda8e7e454d23edb08d4bc3b3f6f872/purge_cache" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
--data '{"purge_everything":true}'
+4 -2
View File
@@ -3,7 +3,7 @@ misc.xml
.DS_Store
node_modules/
*.log
dist/
/dist/
tmp/
coverage/
keys
@@ -14,4 +14,6 @@ obj/
xcuserdata/
*.suo
.idea/
.vscode
.vscode/
*.iml
test/dist/
+8
View File
@@ -0,0 +1,8 @@
{
"tabWidth": 4,
"singleQuote": true,
"printWidth": 100,
"trailingComma": "none",
"quoteProps": "preserve",
"endOfLine": "auto"
}
+41 -5
View File
@@ -2,24 +2,41 @@
Thanks for taking the time to contribute! :gift:
There are different ways to help the project, you will find a summary here.
## Code of conduct
This project and everyone participating in it is governed by the [KeeWeb Code of Conduct](https://github.com/keeweb/keeweb/blob/master/.github/CODE_OF_CONDUCT.md#readme). By participating, you are expected to uphold this code. Please report unacceptable behavior to antelle.net@gmail.com.
This project and everyone participating in it is governed by the [KeeWeb Code of Conduct](https://github.com/keeweb/keeweb/blob/master/.github/CODE_OF_CONDUCT.md#readme).
By participating, you are expected to uphold this code. Please report unacceptable behavior to antelle.net@gmail.com.
## Issues
First, let's check if it's [already there](https://github.com/keeweb/keeweb/issues).
Perhaps, someone has already reported it?
[Click here](https://github.com/keeweb/keeweb/issues/new) to create a new issue.
[Click here](https://github.com/keeweb/keeweb/issues/new/choose) to create a new issue.
When creating issues, please answer some questions asked on that page.
They will help to understand, reproduce and fix your issue.
They will help to understand, reproduce, and fix your issue.
## Vulnerabilities
We would appreciate [responsible disclosure](https://en.wikipedia.org/wiki/Responsible_disclosure).
If you would like to report a vulnerability, the preferred way to do so is [contacting the developer directly](mailto:antelle.net@gmail.com).
## Questions, great ideas, etc...
You can [create an issue](https://github.com/keeweb/keeweb/issues/new) to discuss any question.
You can [create an issue](https://github.com/keeweb/keeweb/issues/new/choose) to discuss any topic.
Indeed, questions on that page are not applicable in this case.
## Development
We don't accept (and in foreseeable future, we won't accept) anyone as a project collaborator directly.
Instead, the code should be contributed via pull requests. To get started with development, take a look at these pages:
- [Architecture](https://github.com/keeweb/keeweb/wiki/Architecture)
- [Engineering](https://github.com/keeweb/keeweb/wiki/Engineering)
- [Unsupported Features](https://github.com/keeweb/keeweb/wiki/Unsupported%20Features)
- [Pull Request Guidelines](https://github.com/keeweb/keeweb/blob/master/.github/PULL_REQUEST_TEMPLATE.md#readme)
## Pull requests
Please follow [this guide](https://github.com/keeweb/keeweb/blob/master/.github/PULL_REQUEST_TEMPLATE.md#readme).
@@ -27,4 +44,23 @@ Please follow [this guide](https://github.com/keeweb/keeweb/blob/master/.github/
## Docs (Wiki pages)
KeeWeb has [Wiki pages](https://github.com/keeweb/keeweb/wiki), however it's not possible to contribute with pull requests.
If you would like to improve it, please [open an issue](https://github.com/keeweb/keeweb/issues/new) and submit your changes in Markdown format.
If you would like to improve it, please [open an issue](https://github.com/keeweb/keeweb/issues/new/choose) and submit your changes in Markdown format.
## Donations
There are two ways of donating:
- join as backer on [OpenCollective](https://opencollective.com/keeweb#support);
- sponsor the developer directly on [GitHub](https://github.com/sponsors/antelle).
Please note: donation does not imply any type of service contract.
## Translations
All KeeWeb translations are contributed by the community. To improve a translation or add a missing one,
join us on [OneSky](https://keeweb.oneskyapp.com).
## PR
We would be happy to support you if you decide to post, blog, or review the project,
or provide any other kind of PR. Please [contact the developer](mailto:antelle.net@gmail.com)
if you have anything to share. You can also poke us on [Twitter](https://twitter.com/kee_web).
+464 -298
View File
@@ -1,14 +1,15 @@
/* eslint-env node */
const fs = require('fs');
const fs = require('fs-extra');
const { execSync } = require('child_process');
const debug = require('debug');
const sass = require('node-sass');
const webpackConfig = require('./webpack.config');
const postCssReplaceFont = require('./build/util/postcss-replace-font');
const webpackConfig = require('./build/webpack.config');
const pkg = require('./package.json');
module.exports = function(grunt) {
debug.enable('electron-notarize');
module.exports = function (grunt) {
require('time-grunt')(grunt);
require('load-grunt-tasks')(grunt);
@@ -22,42 +23,78 @@ module.exports = function(grunt) {
const dt = date.toISOString().replace(/T.*/, '');
const year = date.getFullYear();
const minElectronVersionForUpdate = '4.0.1';
const zipCommentPlaceholderPart = 'zip_comment_placeholder_that_will_be_replaced_with_hash';
const zipCommentPlaceholder = zipCommentPlaceholderPart + '.'.repeat(512 - zipCommentPlaceholderPart.length);
const electronVersion = pkg.dependencies.electron.replace(/^\D/, '');
const skipSign = grunt.option('skip-sign');
const getCodeSignConfig = () =>
skipSign ? { identities: {} } : require('./keys/codesign.json');
let sha = grunt.option('commit-sha');
if (!sha) {
try {
sha = execSync('git rev-parse --short HEAD').toString('utf8').trim();
} catch (e) {
grunt.warn(
"Cannot get commit sha from git. It's recommended to build KeeWeb from a git repo " +
'because commit sha is displayed in the UI, however if you would like to build from a folder, ' +
'you can override what will be displayed in the UI with --commit-sha=xxx.'
);
}
}
grunt.log.writeln(`Building KeeWeb v${pkg.version} (${sha})`);
const webpackOptions = {
date,
beta: !!grunt.option('beta'),
sha,
appleTeamId: '3LE7JZ657W'
};
const windowsAppVersionString = {
CompanyName: 'KeeWeb',
FileDescription: pkg.description,
OriginalFilename: 'KeeWeb.exe',
ProductName: 'KeeWeb',
InternalName: 'KeeWeb'
};
const appdmgOptions = (arch) => ({
title: 'KeeWeb',
icon: 'graphics/icon.icns',
background: 'graphics/dmg-background.png',
'background-color': '#E0E6F9',
'icon-size': 80,
window: { size: { width: 658, height: 498 } },
contents: [
{ x: 438, y: 344, type: 'link', path: '/Applications' },
{
x: 192,
y: 344,
type: 'file',
path: `tmp/desktop/KeeWeb-darwin-${arch}/KeeWeb.app`
}
]
});
const linuxDependencies = [
'libappindicator1',
'libgconf-2-4',
'gnome-keyring',
'libxtst6',
'libx11-6',
'libatspi2.0-0'
];
grunt.initConfig({
gitinfo: {
branch: {
current: {
SHA: 'Current HEAD SHA',
shortSHA: 'Current HEAD short SHA',
name: 'Current branch name',
lastCommitTime: 'Last commit time'
}
}
},
noop: { noop: {} },
clean: {
dist: ['dist', 'tmp'],
desktop: ['tmp/desktop', 'dist/desktop'],
cordova: ['tmp/cordova', 'dist/cordova']
desktop: ['tmp/desktop', 'dist/desktop']
},
copy: {
html: {
src: 'app/index.html',
dest: 'tmp/index.html',
nonull: true
},
favicon: {
src: 'app/favicon.png',
dest: 'tmp/favicon.png',
nonull: true
},
icons: {
cwd: 'app/icons/',
src: ['*.png', '*.svg'],
dest: 'tmp/icons/',
'content-dist': {
cwd: 'app/content/',
src: '**',
dest: 'dist/',
expand: true,
nonull: true
},
@@ -68,13 +105,6 @@ module.exports = function(grunt) {
expand: true,
nonull: true
},
manifest: {
cwd: 'app/manifest/',
src: ['*.json', '*.xml'],
dest: 'tmp/',
expand: true,
nonull: true
},
'dist-manifest': {
cwd: 'app/manifest/',
src: ['*.json', '*.xml'],
@@ -82,12 +112,10 @@ module.exports = function(grunt) {
expand: true,
nonull: true
},
fonts: {
src: 'node_modules/font-awesome/fonts/fontawesome-webfont.*',
dest: 'tmp/fonts/',
nonull: true,
expand: true,
flatten: true
'desktop-html': {
src: 'dist/index.html',
dest: 'tmp/desktop/app/index.html',
nonull: true
},
'desktop-app-content': {
cwd: 'desktop/',
@@ -96,38 +124,18 @@ module.exports = function(grunt) {
expand: true,
nonull: true
},
'desktop-update': {
cwd: 'tmp/desktop/KeeWeb-darwin-x64/KeeWeb.app/Contents/Resources/',
src: 'app.asar',
dest: 'tmp/desktop/update/',
expand: true,
nonull: true
},
'desktop-update-helper': {
src: ['helper/darwin/KeeWebHelper', 'helper/win32/KeeWebHelper.exe'],
dest: 'tmp/desktop/update/',
nonull: true
},
'desktop-windows-helper-ia32': {
src: 'helper/win32/KeeWebHelper.exe',
dest: 'tmp/desktop/KeeWeb-win32-ia32/Resources/',
nonull: true
},
'desktop-windows-helper-x64': {
src: 'helper/win32/KeeWebHelper.exe',
dest: 'tmp/desktop/KeeWeb-win32-x64/Resources/',
nonull: true
},
'desktop-darwin-helper-x64': {
src: 'helper/darwin/KeeWebHelper',
dest: 'tmp/desktop/KeeWeb-darwin-x64/KeeWeb.app/Contents/Resources/',
nonull: true,
options: { mode: '0755' }
},
'desktop-darwin-installer': {
cwd: 'package/osx/KeeWeb Installer.app',
dest: 'tmp/desktop/KeeWeb-darwin-x64/KeeWeb.app/Contents/Installer/KeeWeb Installer.app',
'desktop-darwin-installer-helper-x64': {
cwd: 'tmp/desktop/KeeWeb Installer.app',
src: '**',
dest: 'tmp/desktop/KeeWeb-darwin-x64/KeeWeb.app/Contents/Installer/KeeWeb Installer.app',
expand: true,
nonull: true,
options: { mode: true }
},
'desktop-darwin-installer-helper-arm64': {
cwd: 'tmp/desktop/KeeWeb Installer.app',
src: '**',
dest: 'tmp/desktop/KeeWeb-darwin-arm64/KeeWeb.app/Contents/Installer/KeeWeb Installer.app',
expand: true,
nonull: true,
options: { mode: true }
@@ -141,36 +149,104 @@ module.exports = function(grunt) {
src: 'tmp/desktop/KeeWeb.win.ia32.exe',
dest: `dist/desktop/KeeWeb-${pkg.version}.win.ia32.exe`,
nonull: true
},
'desktop-win32-dist-arm64': {
src: 'tmp/desktop/KeeWeb.win.arm64.exe',
dest: `dist/desktop/KeeWeb-${pkg.version}.win.arm64.exe`,
nonull: true
},
'native-modules-darwin-x64': {
src: 'node_modules/@keeweb/keeweb-native-modules/*-darwin-x64.node',
dest: 'tmp/desktop/KeeWeb-darwin-x64/KeeWeb.app/Contents/Resources/',
nonull: true
},
'native-modules-darwin-arm64': {
src: 'node_modules/@keeweb/keeweb-native-modules/*-darwin-arm64.node',
dest: 'tmp/desktop/KeeWeb-darwin-arm64/KeeWeb.app/Contents/Resources/',
nonull: true
},
'native-modules-win32-x64': {
src: 'node_modules/@keeweb/keeweb-native-modules/*-win32-x64.node',
dest: 'tmp/desktop/KeeWeb-win32-x64/resources/',
nonull: true
},
'native-modules-win32-ia32': {
src: 'node_modules/@keeweb/keeweb-native-modules/*-win32-ia32.node',
dest: 'tmp/desktop/KeeWeb-win32-ia32/resources/',
nonull: true
},
'native-modules-win32-arm64': {
src: 'node_modules/@keeweb/keeweb-native-modules/*-win32-arm64.node',
dest: 'tmp/desktop/KeeWeb-win32-arm64/resources/',
nonull: true
},
'native-modules-linux-x64': {
src: 'node_modules/@keeweb/keeweb-native-modules/*-linux-x64.node',
dest: 'tmp/desktop/keeweb-linux-x64/resources/',
nonull: true
},
'electron-builder-dist-linux-rpm': {
src: `tmp/desktop/electron-builder/KeeWeb-${pkg.version}.x86_64.rpm`,
dest: `dist/desktop/KeeWeb-${pkg.version}.linux.x86_64.rpm`,
nonull: true
},
'electron-builder-dist-linux-snap': {
src: `tmp/desktop/electron-builder/KeeWeb_${pkg.version}_amd64.snap`,
dest: `dist/desktop/KeeWeb-${pkg.version}.linux.snap`,
nonull: true
},
'electron-builder-dist-linux-appimage': {
src: `tmp/desktop/electron-builder/keeweb-${pkg.version}.AppImage`,
dest: `dist/desktop/KeeWeb-${pkg.version}.linux.AppImage`,
nonull: true
},
'darwin-installer-icon': {
src: 'graphics/icon.icns',
dest: 'tmp/desktop/KeeWeb Installer.app/Contents/Resources/applet.icns',
nonull: true
},
'native-messaging-host-darwin-x64': {
src: 'node_modules/@keeweb/keeweb-native-messaging-host/darwin-x64/keeweb-native-messaging-host',
dest: 'tmp/desktop/KeeWeb-darwin-x64/KeeWeb.app/Contents/MacOS/util/keeweb-native-messaging-host',
nonull: true,
options: { mode: '0755' }
},
'native-messaging-host-darwin-arm64': {
src: 'node_modules/@keeweb/keeweb-native-messaging-host/darwin-arm64/keeweb-native-messaging-host',
dest: 'tmp/desktop/KeeWeb-darwin-arm64/KeeWeb.app/Contents/MacOS/util/keeweb-native-messaging-host',
nonull: true,
options: { mode: '0755' }
},
'native-messaging-host-linux-x64': {
src: 'node_modules/@keeweb/keeweb-native-messaging-host/linux-x64/keeweb-native-messaging-host',
dest: 'tmp/desktop/keeweb-linux-x64/keeweb-native-messaging-host',
nonull: true,
options: { mode: '0755' }
},
'native-messaging-host-win32-x64': {
src: 'node_modules/@keeweb/keeweb-native-messaging-host/win32-x64/keeweb-native-messaging-host.exe',
dest: 'tmp/desktop/KeeWeb-win32-x64/keeweb-native-messaging-host.exe',
nonull: true
},
'native-messaging-host-win32-ia32': {
src: 'node_modules/@keeweb/keeweb-native-messaging-host/win32-ia32/keeweb-native-messaging-host.exe',
dest: 'tmp/desktop/KeeWeb-win32-ia32/keeweb-native-messaging-host.exe',
nonull: true
},
'native-messaging-host-win32-arm64': {
src: 'node_modules/@keeweb/keeweb-native-messaging-host/win32-arm64/keeweb-native-messaging-host.exe',
dest: 'tmp/desktop/KeeWeb-win32-arm64/keeweb-native-messaging-host.exe',
nonull: true
}
},
eslint: {
app: ['app/scripts/**/*.js'],
desktop: ['desktop/**/*.js', '!desktop/node_modules/**'],
grunt: ['Gruntfile.js', 'grunt/**/*.js']
},
sass: {
options: {
sourceMap: false,
includePaths: ['./node_modules'],
implementation: sass
},
dist: {
files: {
'tmp/css/main.css': 'app/styles/main.scss'
}
}
},
postcss: {
options: {
processors: [
postCssReplaceFont,
require('cssnano')({discardComments: {removeAll: true}})
]
},
dist: {
src: 'tmp/css/main.css',
dest: 'tmp/css/main.css'
}
app: ['app/scripts/**/*.js', 'app/scripts/**/*.ts'],
test: ['test/**/*.ts'],
desktop: ['desktop/**/*.js'],
build: ['Gruntfile.js', 'grunt.*.js', 'build/**/*.js', 'webpack.config.js'],
plugins: ['plugins/**/*.js'],
util: ['util/**/*.js'],
installer: ['package/osx/installer.js']
},
inline: {
app: {
@@ -178,6 +254,19 @@ module.exports = function(grunt) {
dest: 'tmp/app.html'
}
},
'csp-hashes': {
options: {
algo: 'sha512',
expected: {
style: 1,
script: 1
}
},
app: {
src: 'tmp/app.html',
dest: 'dist/index.html'
}
},
htmlmin: {
options: {
removeComments: true,
@@ -185,151 +274,176 @@ module.exports = function(grunt) {
},
app: {
files: {
'dist/index.html': 'tmp/app.html'
'tmp/app.html': 'tmp/app.html'
}
}
},
'string-replace': {
manifest: {
'update-manifest': {
options: {
replacements: [
{ pattern: '# YYYY-MM-DD:v0.0.0', replacement: '# ' + dt + ':v' + pkg.version },
{ pattern: '# updmin:v0.0.0', replacement: '# updmin:v' + minElectronVersionForUpdate }
{
pattern: /"version":\s*".*?"/,
replacement: `"version": "${pkg.version}"`
},
{
pattern: /"date":\s*".*?"/,
replacement: `"date": "${dt}"`
}
]
},
files: { 'dist/manifest.appcache': 'app/manifest.appcache' }
files: { 'dist/update.json': 'app/update.json' }
},
'manifest-html': {
options: { replacements: [{ pattern: '<html', replacement: '<html manifest="manifest.appcache"' }] },
files: { 'dist/index.html': 'dist/index.html' }
},
'desktop-html': {
options: { replacements: [{ pattern: ' manifest="manifest.appcache"', replacement: '' }] },
files: { 'tmp/desktop/app/index.html': 'dist/index.html' }
'service-worker': {
options: { replacements: [{ pattern: '0.0.0', replacement: pkg.version }] },
files: { 'dist/service-worker.js': 'app/service-worker.js' }
},
'desktop-public-key': {
options: { replacements: [{ pattern: '\'@@PUBLIC_KEY_CONTENT\'', replacement:
'`' + fs.readFileSync('app/resources/public-key.pem', {encoding: 'utf8'}).trim() + '`' }] },
options: {
replacements: [
{
pattern: "'@@PUBLIC_KEY_CONTENT'",
replacement:
'`' +
fs
.readFileSync('app/resources/public-key.pem', {
encoding: 'utf8'
})
.trim() +
'`'
}
]
},
files: { 'tmp/desktop/app/main.js': 'desktop/main.js' }
},
'cordova-html': {
options: { replacements: [{ pattern: '<script', replacement: '<script src="cordova.js"></script><script' }] },
files: { 'tmp/cordova/app/index.html': 'dist/index.html' }
}
},
webpack: {
js: webpackConfig.config(grunt)
},
'webpack-dev-server': {
options: {
webpack: webpackConfig.devServerConfig(grunt),
publicPath: '/tmp/js',
progress: false
},
js: {
keepalive: true,
port: 8085
}
},
uglify: {
options: {
preserveComments: false
},
app: {
files: { 'tmp/js/app.js': ['tmp/js/app.js'] }
},
vendor: {
options: {
mangle: false,
compress: false
},
files: { 'tmp/js/vendor.js': ['tmp/js/vendor.js'] }
}
},
watch: {
options: {
interrupt: true,
debounceDelay: 500
},
styles: {
files: 'app/styles/**/*.scss',
tasks: ['sass']
},
indexhtml: {
files: 'app/index.html',
tasks: ['copy:html']
}
app: webpackConfig.config(webpackOptions)
},
electron: {
options: {
name: 'KeeWeb',
dir: 'tmp/desktop/app',
out: 'tmp/desktop',
electronVersion: electronVersion,
electronVersion,
overwrite: true,
asar: true,
'appCopyright': `Copyright © ${year} Antelle`,
'appVersion': pkg.version,
'buildVersion': '<%= gitinfo.local.branch.current.shortSHA %>'
appCopyright: `Copyright © ${year} Antelle`,
appVersion: pkg.version,
buildVersion: sha
},
linux: {
options: {
name: 'keeweb',
platform: 'linux',
arch: ['x64', 'ia32'],
arch: 'x64',
icon: 'graphics/icon.ico'
}
},
darwin: {
'darwin-x64': {
options: {
platform: 'darwin',
arch: ['x64'],
arch: 'x64',
icon: 'graphics/icon.icns',
'appBundleId': 'net.antelle.keeweb',
'appCategoryType': 'public.app-category.productivity',
'extendInfo': 'package/osx/extend.plist'
appBundleId: 'net.antelle.keeweb',
appCategoryType: 'public.app-category.productivity',
extendInfo: 'package/osx/extend.plist'
}
},
win32: {
'darwin-arm64': {
options: {
platform: 'darwin',
arch: 'arm64',
icon: 'graphics/icon.icns',
appBundleId: 'net.antelle.keeweb',
appCategoryType: 'public.app-category.productivity',
extendInfo: 'package/osx/extend.plist'
}
},
'win32-x64': {
options: {
platform: 'win32',
arch: ['ia32', 'x64'],
arch: 'x64',
icon: 'graphics/icon.ico',
'buildVersion': pkg.version,
'version-string': {
'CompanyName': 'KeeWeb',
'FileDescription': pkg.description,
'OriginalFilename': 'KeeWeb.exe',
'ProductName': 'KeeWeb',
'InternalName': 'KeeWeb'
buildVersion: pkg.version,
'version-string': windowsAppVersionString
}
},
'win32-ia32': {
options: {
platform: 'win32',
arch: 'ia32',
icon: 'graphics/icon.ico',
buildVersion: pkg.version,
'version-string': windowsAppVersionString
}
},
'win32-arm64': {
options: {
platform: 'win32',
arch: 'arm64',
icon: 'graphics/icon.ico',
buildVersion: pkg.version,
'version-string': windowsAppVersionString
}
}
},
'electron-builder': {
linux: {
options: {
publish: 'never',
targets: 'linux',
prepackaged: 'tmp/desktop/keeweb-linux-x64',
config: {
appId: 'net.antelle.keeweb',
productName: 'keeweb',
copyright: `Copyright © ${year} Antelle`,
directories: {
output: 'tmp/desktop/electron-builder',
app: 'desktop',
buildResources: 'graphics'
},
fileAssociations: {
ext: 'kdbx',
name: 'KeePass 2 database',
mimeType: 'application/x-keepass2'
},
linux: {
target: ['AppImage', 'snap', 'rpm'],
category: 'Utility'
},
rpm: {
// depends: linuxDependencies
},
snap: {
stagePackages: linuxDependencies
}
}
}
}
},
codesign: {
app: {
options: {
identity: 'app',
deep: true
},
src: ['tmp/desktop/KeeWeb-darwin-x64/KeeWeb.app']
'electron-patch': {
'win32-x64': 'tmp/desktop/KeeWeb-win32-x64/KeeWeb.exe',
'win32-ia32': 'tmp/desktop/KeeWeb-win32-ia32/KeeWeb.exe',
'win32-arm64': 'tmp/desktop/KeeWeb-win32-arm64/KeeWeb.exe',
'darwin-x64': 'tmp/desktop/KeeWeb-darwin-x64/KeeWeb.app',
'darwin-arm64': 'tmp/desktop/KeeWeb-darwin-arm64/KeeWeb.app',
'linux': 'tmp/desktop/KeeWeb-linux-x64/keeweb'
},
osacompile: {
options: {
language: 'JavaScript'
},
dmg: {
options: {
identity: 'app'
},
src: [`dist/desktop/KeeWeb-${pkg.version}.mac.dmg`]
installer: {
files: {
'tmp/desktop/KeeWeb Installer.app': 'package/osx/installer.js'
}
}
},
compress: {
options: {
level: 6
},
'desktop-update': {
options: { archive: 'dist/desktop/UpdateDesktop.zip', comment: zipCommentPlaceholder },
files: [
{ cwd: 'tmp/desktop/update', src: '**', expand: true, nonull: true }
]
},
'win32-x64': {
options: { archive: `dist/desktop/KeeWeb-${pkg.version}.win.x64.zip` },
files: [{ cwd: 'tmp/desktop/KeeWeb-win32-x64', src: '**', expand: true }]
@@ -338,39 +452,33 @@ module.exports = function(grunt) {
options: { archive: `dist/desktop/KeeWeb-${pkg.version}.win.ia32.zip` },
files: [{ cwd: 'tmp/desktop/KeeWeb-win32-ia32', src: '**', expand: true }]
},
'win32-arm64': {
options: { archive: `dist/desktop/KeeWeb-${pkg.version}.win.arm64.zip` },
files: [{ cwd: 'tmp/desktop/KeeWeb-win32-arm64', src: '**', expand: true }]
},
'linux-x64': {
options: { archive: `dist/desktop/KeeWeb-${pkg.version}.linux.x64.zip` },
files: [{ cwd: 'tmp/desktop/KeeWeb-linux-x64', src: '**', expand: true },
{ cwd: 'graphics', src: '128x128.png', nonull: true, expand: true }]
},
'linux-ia32': {
options: { archive: `dist/desktop/KeeWeb-${pkg.version}.linux.ia32.zip` },
files: [{ cwd: 'tmp/desktop/KeeWeb-linux-ia32', src: '**', expand: true },
{ cwd: 'graphics', src: '128x128.png', nonull: true, expand: true }]
files: [
{ cwd: 'tmp/desktop/keeweb-linux-x64', src: '**', expand: true },
{ cwd: 'graphics', src: '128x128.png', nonull: true, expand: true }
]
}
},
appdmg: {
options: {
title: 'KeeWeb',
icon: 'graphics/icon.icns',
background: 'graphics/background.png',
'background-color': '#E0E6F9',
'icon-size': 80,
window: { size: { width: 658, height: 498 } },
contents: [
{ x: 438, y: 344, type: 'link', path: '/Applications' },
{ x: 192, y: 344, type: 'file', path: 'tmp/desktop/KeeWeb-darwin-x64/KeeWeb.app' }
]
x64: {
options: appdmgOptions('x64'),
dest: `dist/desktop/KeeWeb-${pkg.version}.mac.x64.dmg`
},
app: {
dest: `dist/desktop/KeeWeb-${pkg.version}.mac.dmg`
arm64: {
options: appdmgOptions('arm64'),
dest: `dist/desktop/KeeWeb-${pkg.version}.mac.arm64.dmg`
}
},
nsis: {
options: {
vars: {
version: pkg.version,
rev: function() { return grunt.config.get('gitinfo.local.branch.current.shortSHA'); },
rev: sha,
homepage: pkg.homepage
}
},
@@ -401,6 +509,28 @@ module.exports = function(grunt) {
arch: 'ia32',
output: 'tmp/desktop/KeeWeb-win32-ia32/uninst.exe'
}
},
'win32-arm64': {
options: {
installScript: 'package/nsis/main.nsi',
arch: 'arm64',
output: 'tmp/desktop/KeeWeb.win.arm64.exe'
}
},
'win32-un-arm64': {
options: {
installScript: 'package/nsis/main-un.nsi',
arch: 'arm64',
output: 'tmp/desktop/KeeWeb-win32-arm64/uninst.exe'
}
}
},
chmod: {
'linux-desktop-x64': {
options: {
mode: '4755'
},
src: ['tmp/desktop/keeweb-linux-x64/chrome-sandbox']
}
},
deb: {
@@ -412,7 +542,7 @@ module.exports = function(grunt) {
description: pkg.description,
author: pkg.author,
homepage: pkg.homepage,
rev: function() { return grunt.config.get('gitinfo.local.branch.current.shortSHA'); }
rev: sha
}
},
'linux-x64': {
@@ -422,7 +552,7 @@ module.exports = function(grunt) {
pkgName: `KeeWeb-${pkg.version}.linux.x64.deb`,
targetDir: 'dist/desktop',
appName: 'KeeWeb',
depends: 'libappindicator1, libgconf2-4',
depends: linuxDependencies.join(', '),
scripts: {
postinst: 'package/deb/scripts/postinst'
}
@@ -430,82 +560,86 @@ module.exports = function(grunt) {
},
files: [
{ cwd: 'package/deb/usr', src: '**', dest: '/usr', expand: true, nonull: true },
{ cwd: 'tmp/desktop/KeeWeb-linux-x64/', src: '**', dest: '/opt/keeweb-desktop', expand: true, nonull: true },
{ src: 'graphics/128x128.png', dest: '/usr/share/icons/hicolor/128x128/apps/keeweb.png', nonull: true }
{
cwd: 'tmp/desktop/keeweb-linux-x64/',
src: '**',
dest: '/usr/share/keeweb-desktop',
expand: true,
nonull: true
},
{
src: 'graphics/128x128.png',
dest: '/usr/share/icons/hicolor/128x128/apps/keeweb.png',
nonull: true
}
]
}
},
'osx-sign': {
options: {
get identity() {
return getCodeSignConfig().identities.app;
},
hardenedRuntime: true,
entitlements: 'package/osx/entitlements.plist',
'entitlements-inherit': 'package/osx/entitlements-inherit.plist',
'gatekeeper-assess': false
},
'linux-ia32': {
'desktop-x64': {
options: {
info: {
arch: 'i386',
pkgName: `KeeWeb-${pkg.version}.linux.ia32.deb`,
targetDir: 'dist/desktop',
appName: 'KeeWeb',
depends: 'libappindicator1, libgconf2-4',
scripts: {
postinst: 'package/deb/scripts/postinst'
}
}
'provisioning-profile': './keys/keeweb.provisionprofile'
},
files: [
{ cwd: 'package/deb/usr', src: '**', dest: '/usr', expand: true, nonull: true },
{ cwd: 'tmp/desktop/KeeWeb-linux-ia32/', src: '**', dest: '/opt/keeweb-desktop', expand: true, nonull: true },
{ src: 'graphics/128x128.png', dest: '/usr/share/icons/hicolor/128x128/apps/keeweb.png', nonull: true }
]
src: 'tmp/desktop/KeeWeb-darwin-x64/KeeWeb.app'
},
'desktop-arm64': {
options: {
'provisioning-profile': './keys/keeweb.provisionprofile'
},
src: 'tmp/desktop/KeeWeb-darwin-arm64/KeeWeb.app'
},
'installer': {
src: 'tmp/desktop/KeeWeb Installer.app'
}
},
'sign-archive': {
'desktop-update': {
options: {
file: 'dist/desktop/UpdateDesktop.zip',
signature: zipCommentPlaceholder
}
}
},
'sign-desktop-files': {
'desktop-update': {
options: {
path: 'tmp/desktop/update'
}
}
},
'validate-desktop-update': {
desktop: {
options: {
file: 'dist/desktop/UpdateDesktop.zip',
expected: [
'app.asar',
'helper/darwin/KeeWebHelper',
'helper/win32/KeeWebHelper.exe'
],
expectedCount: 7,
publicKey: 'app/resources/public-key.pem'
}
}
},
'sign-html': {
'app': {
options: {
file: 'dist/index.html',
skip: grunt.option('skip-sign')
notarize: {
options: {
appBundleId: 'net.antelle.keeweb',
get appleId() {
return getCodeSignConfig().appleId;
},
appleIdPassword: '@keychain:AC_PASSWORD',
get ascProvider() {
return getCodeSignConfig().teamId;
}
},
'desktop-x64': {
src: 'tmp/desktop/KeeWeb-darwin-x64/KeeWeb.app'
},
'desktop-arm64': {
src: 'tmp/desktop/KeeWeb-darwin-arm64/KeeWeb.app'
}
},
'sign-exe': {
options: {
spc: 'keys/keeweb.spc',
key: '01',
algo: 'sha256',
url: pkg.homepage
url: pkg.homepage,
get windows() {
return getCodeSignConfig().windows;
},
get certHash() {
return getCodeSignConfig().microsoftCertHash;
}
},
'win32-build-x64': {
options: {
files: {
'tmp/desktop/KeeWeb-win32-x64/KeeWeb.exe': 'KeeWeb',
'tmp/desktop/KeeWeb-win32-x64/keeweb-native-messaging-host.exe':
'KeeWeb Native Messaging Host',
'tmp/desktop/KeeWeb-win32-x64/ffmpeg.dll': '',
'tmp/desktop/KeeWeb-win32-x64/libEGL.dll': 'ANGLE libEGL Dynamic Link Library',
'tmp/desktop/KeeWeb-win32-x64/libGLESv2.dll': 'ANGLE libGLESv2 Dynamic Link Library',
'tmp/desktop/KeeWeb-win32-x64/osmesa.dll': ''
'tmp/desktop/KeeWeb-win32-x64/libEGL.dll':
'ANGLE libEGL Dynamic Link Library',
'tmp/desktop/KeeWeb-win32-x64/libGLESv2.dll':
'ANGLE libGLESv2 Dynamic Link Library'
}
}
},
@@ -513,10 +647,27 @@ module.exports = function(grunt) {
options: {
files: {
'tmp/desktop/KeeWeb-win32-ia32/KeeWeb.exe': 'KeeWeb',
'tmp/desktop/KeeWeb-win32-ia32/keeweb-native-messaging-host.exe':
'KeeWeb Native Messaging Host',
'tmp/desktop/KeeWeb-win32-ia32/ffmpeg.dll': '',
'tmp/desktop/KeeWeb-win32-ia32/libEGL.dll': 'ANGLE libEGL Dynamic Link Library',
'tmp/desktop/KeeWeb-win32-ia32/libGLESv2.dll': 'ANGLE libGLESv2 Dynamic Link Library',
'tmp/desktop/KeeWeb-win32-ia32/osmesa.dll': ''
'tmp/desktop/KeeWeb-win32-ia32/libEGL.dll':
'ANGLE libEGL Dynamic Link Library',
'tmp/desktop/KeeWeb-win32-ia32/libGLESv2.dll':
'ANGLE libGLESv2 Dynamic Link Library'
}
}
},
'win32-build-arm64': {
options: {
files: {
'tmp/desktop/KeeWeb-win32-arm64/KeeWeb.exe': 'KeeWeb',
'tmp/desktop/KeeWeb-win32-arm64/keeweb-native-messaging-host.exe':
'KeeWeb Native Messaging Host',
'tmp/desktop/KeeWeb-win32-arm64/ffmpeg.dll': '',
'tmp/desktop/KeeWeb-win32-arm64/libEGL.dll':
'ANGLE libEGL Dynamic Link Library',
'tmp/desktop/KeeWeb-win32-arm64/libGLESv2.dll':
'ANGLE libGLESv2 Dynamic Link Library'
}
}
},
@@ -534,6 +685,13 @@ module.exports = function(grunt) {
}
}
},
'win32-uninst-arm64': {
options: {
files: {
'tmp/desktop/KeeWeb-win32-arm64/uninst.exe': 'KeeWeb Uninstaller'
}
}
},
'win32-installer-x64': {
options: {
files: {
@@ -547,26 +705,34 @@ module.exports = function(grunt) {
'tmp/desktop/KeeWeb.win.ia32.exe': 'KeeWeb Setup'
}
}
},
'win32-installer-arm64': {
options: {
files: {
'tmp/desktop/KeeWeb.win.arm64.exe': 'KeeWeb Setup'
}
}
}
},
'concurrent': {
options: {
logConcurrentOutput: true
},
'dev-server': [
'watch:styles',
'webpack-dev-server'
]
},
'sign-dist': {
'dist': {
dist: {
options: {
sign: 'dist/desktop/Verify.sign.sha256'
},
files: {
'dist/desktop/Verify.sha256': ['dist/desktop/KeeWeb-*', 'dist/desktop/UpdateDesktop.zip']
'dist/desktop/Verify.sha256': ['dist/desktop/KeeWeb-*']
}
}
},
virustotal: {
options: {
prefix: `keeweb.v${pkg.version}-${sha}.`,
timeout: 10 * 60 * 1000,
get apiKey() {
return require('./keys/virus-total.json').apiKey;
}
},
html: 'dist/index.html'
}
});
};
+1 -1
View File
@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2019 Antelle
Copyright (c) 2021 Antelle https://antelle.net
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+41 -20
View File
@@ -5,22 +5,22 @@ The app can run either in browser, or as a desktop app.
![screenshot](img/screenshot.png)
# Quick Links
## Quick Links
Apps: [Web](https://app.keeweb.info/), [Desktop](https://github.com/keeweb/keeweb/releases/latest)
Timeline: [Release Notes](release-notes.md), [TODO](https://github.com/keeweb/keeweb/wiki/TODO)
On one page: [Features](https://keeweb.info/#features), [FAQ](https://github.com/keeweb/keeweb/wiki/FAQ)
Website: [keeweb.info](https://keeweb.info)
Twitter: [kee_web](https://twitter.com/kee_web)
Donate: [OpenCollective](https://opencollective.com/keeweb#support), [GitHub](https://github.com/sponsors/antelle)
# Status
## Status
The app is already rather stable, so basic stuff should work.
Project roadmap with planned features and approximate schedule is on [TODO](https://github.com/keeweb/keeweb/wiki/TODO) page.
The app is quite stable now. Basic stuff, as well as more advanced operations, should be rather reliable.
# Self-hosting
## Self-hosting
Everything you need to host this app on your server is any static file server. The app is a single HTML file + cache manifest (optionally; for offline access).
Everything you need to host this app on your server is any static file server. The app is a single HTML file + a service worker (optionally; for offline access).
You can download the latest distribution files from [gh-pages](https://github.com/keeweb/keeweb/archive/gh-pages.zip) branch.
If you are using Docker:
@@ -33,47 +33,68 @@ docker run --name keeweb -d -p 443:443 -p 80:80 -v $EXT_DIR:/etc/nginx/external/
To make Dropbox work in your self-hosted app, [go to this Wiki page](https://github.com/keeweb/keeweb/wiki/Dropbox-and-GDrive).
# Building
## Building
The easiest way to clone all KeeWeb repos is:
```bash
curl https://raw.githubusercontent.com/keeweb/keeweb/develop/dev-env.sh | bash -
```
The app can be built with grunt: `grunt` (html file will be in `dist/`).
Desktop apps are built with `grunt desktop`. This works only in macOS as it builds dmg; requires wine.
Also, a hardware token is required.
To run Electron app without building an installer, build the app with `grunt` and start it this way:
The app can be built with grunt: `grunt` (html files will be in `dist/`).
Desktop apps are built with `grunt desktop`. This requires some magic and currently works only on CI,
you can find more details in [the GitHub Actions workflow](.github/workflows/build.yaml).
To run the desktop (electron) app in development mode, start it this way:
```bash
grunt dev
npm run-script electron
npm run dev
npm run electron
```
For debug build:
1. run `grunt dev`
2. open `http://localhost:8085/tmp`
1. run `npm run dev`
2. open `http://localhost:8085`
# Contributing
To build desktop apps, use these goals, the result can be found in `tmp`:
```
npm run dev-desktop-macos
npm run dev-desktop-windows
npm run dev-desktop-linux
```
## Contributing
Please read contribution guidelines [for pull requests](.github/PULL_REQUEST_TEMPLATE.md).
Here's a [list of issues](https://github.com/keeweb/keeweb/labels/help%20wanted) where your help would be very welcome.
Also you can help by [translating KeeWeb](https://keeweb.oneskyapp.com) to your language.
### Important notes for pull requests
Other ways of contribution can be found [on this page](CONTRIBUTING.md).
#### Important notes for pull requests
- please branch from `develop`, not `master`
- don't edit translation files except base.json, they will be replaced
# Donations
## Donations
KeeWeb is not free to develop. It takes time, requires paid code signing certificates and domains.
You can help the project or say "thank you" with this button:
[<img src="img/paypal-donate.png" alt="Donate with PayPal" width="100">](https://www.paypal.me/dvitkovsky)
[<img src="https://opencollective.com/keeweb/tiers/backer.svg?avatarHeight=42&width=880" alt="OpenCollective">](https://opencollective.com/keeweb#support)
You can also sponsor the developer directly [on GitHub](https://github.com/sponsors/antelle).
Please note: donation does not imply any type of service contract.
## Thank you
# License
Notable contributions to KeeWeb:
- Florian Reuschel ([@Loilo](https://github.com/Loilo)): [German translation](https://keeweb.oneskyapp.com/collaboration/translate/project/project/173183/language/550)
- Dennis Ploeger ([@dploeger](https://github.com/dploeger)): [auto-type improvements](https://github.com/keeweb/keeweb/pulls?q=is%3Apr+is%3Aclosed+author%3Adploeger)
- Hackmanit ([hackmanit.de](https://www.hackmanit.de)): [penetration test](https://www.hackmanit.de/en/blog-en/104-pro-bono-penetration-test-keeweb)
- Peter Bittner ([@bittner](https://github.com/bittner)): [Wikipedia article](https://en.wikipedia.org/wiki/KeeWeb)
## License
[MIT](https://github.com/keeweb/keeweb/blob/master/LICENSE)
+11
View File
@@ -0,0 +1,11 @@
# Security Policy
## Supported Versions
Only the latest version of the product is supported. This version can be accessed at https://app.keeweb.info
and downloaded from https://keeweb.info or GitHub releases ([latest release link](https://github.com/keeweb/keeweb/releases/latest)).
## Reporting a Vulnerability
We would appreciate [responsible disclosure](https://en.wikipedia.org/wiki/Responsible_disclosure).
If you would like to report a vulnerability, the preferred way to do so is [contacting the developer directly](mailto:antelle.net@gmail.com).
+28
View File
@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Not Found</title>
<style>
body {
font-family: -apple-system, 'BlinkMacSystemFont', 'Raleway', 'Helvetica Neue',
'Helvetica', 'Arial', sans-serif;
font-feature-settings: 'liga' 0;
text-align: center;
background: #f5f5f5;
font-weight: 300;
}
h1 {
font-size: 3em;
margin-top: 10vh;
}
p {
line-height: 1.5em;
}
</style>
</head>
<body>
<h1>404 Not Found</h1>
<p>Sorry, the page you're looking for was not found.</p>
</body>
</html>
+16
View File
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>KeeWeb</title>
</head>
<body>
<script>
window.opener.postMessage(
{ storage: 'dropbox', search: location.search },
window.location.origin
);
window.close();
</script>
</body>
</html>
+16
View File
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>KeeWeb</title>
</head>
<body>
<script>
window.opener.postMessage(
{ storage: 'gdrive', search: location.search },
window.location.origin
);
window.close();
</script>
</body>
</html>
+16
View File
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>KeeWeb</title>
</head>
<body>
<script>
window.opener.postMessage(
{ storage: 'onedrive', search: location.search },
window.location.origin
);
window.close();
</script>
</body>
</html>
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 685 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

+1 -1
View File
@@ -1 +1 @@
<svg version="1" xmlns="http://www.w3.org/2000/svg" width="922.667" height="922.667" viewBox="0 0 692.000000 692.000000"><path d="M266.9 57.4c-.2.2-4 .6-8.3 1-4.4.4-8.2.8-8.5 1-.3.2-2.7.7-5.3 1-5.5.7-21.6 4.8-29.8 7.5-46.3 15.4-93.3 48.9-126.5 90.1-25.7 31.8-46.8 74.8-52.9 107.4-.5 2.8-1.5 8.3-2.1 12.1-1.9 11.6-2.6 35.9-1.3 45 .3 2.7.9 7 1.2 9.5 3.3 27.4 16.9 55.4 36.1 74.5 12.1 12.1 27.3 22.7 40 27.8 3.9 1.6 7.9 3.3 9 3.7 1.1.5 4.3 1.5 7 2.4 4.4 1.3 7.1 1.9 18.5 4.1 12.1 2.4 42.4 2.4 56.5 0 1.7-.3 4.4-.7 6-1 1.7-.3 4.1-.7 5.5-1 1.4-.3 3.7-.7 5.1-1 4.5-.8 19.1-5.2 28.4-8.6 16.8-6.1 42.9-20.2 59.4-32.2l5.3-3.9 130.7 130.5C567.7 654 571.7 657.8 577.5 660c6.2 2.2 15.3 2.9 21.4 1.6 12.8-2.7 27.8-15.7 34.7-30.1 2.5-5.3 2.9-7.1 2.9-15-.1-15.8 1.1-14.3-49.6-65.1l-44-44 18.1-18.2 18.1-18.1 6.7 7.1c20.7 21.9 32.6 32.8 38.6 35.3 5.6 2.4 11.5-1.2 26.5-15.8 16.1-15.8 21.8-23.8 20-28.6-.9-2.3-4.6-7.8-7.4-10.7-.5-.6-4.1-4.8-8-9.2-7.2-8.3-64.7-65.9-91-91.1-8.2-7.9-16-14.7-17.3-15.2-6.8-2.6-12.6.8-28.4 16.3-13.1 12.9-19.8 21.8-19.8 26.3 0 5.6 13.3 21 37.4 43.4l5.8 5.4-18.1 18.1-18.1 18.1-67-67c-36.9-36.8-67-67.3-67-67.7 0-.4 3-5.1 6.7-10.4 16.1-23.5 30.3-53.8 35.8-76.4.7-2.8 4.3-22.5 5.3-28.5 1.1-6.5.8-41.1-.3-48.5-1.4-9.2-6.4-26.8-10-35.3-9.9-23.3-28.4-44.9-50.5-58.8-21.8-13.8-47.4-20.5-78.6-20.7-7.3-.1-13.3 0-13.5.2zm22 74c12.1 2.8 22.6 7.6 31.1 14.4 13.3 10.7 23.7 27.4 26.3 42.7 6 34.4-9.5 65.3-40.5 80.7-16.1 7.9-40.9 8.5-58.1 1.3-4.4-1.8-5.2-1.9-4-.3 1.1 1.4 4 9.8 4.8 13.9 5.3 25.7-.6 47.7-17.7 66-8.9 9.6-19.7 16.4-31.3 19.8-9.7 2.9-11.7 3.1-22.2 3.2-24.8 0-47.2-12.3-61-33.3-15.4-23.7-15.3-56.4.4-79.3 11.1-16.2 26.6-27.1 44.3-31.1 14.4-3.2 32.9-1.7 43.9 3.7 2 .9 3.7 1.6 3.8 1.5.2-.2-.8-3.4-2.2-7.3-3.4-9.7-3.7-11.4-4-23.3-.4-17.1 3.8-30.7 13.8-44 11.4-15.2 26.5-24.8 44.7-28.4 6.2-1.2 22.9-1.4 27.9-.2z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-64 -64 640 640"><path d="M136.736 512c-4.892-.008-10.322-2.061-15.92-4.997-11.941-6.265-20.13-14.185-13.293-27.218l166.101-316.638c-1.972-1.022-3.619-1.88-4.743-2.469-59.892-31.418-86.463-77.87-64.952-118.877 24.726-47.135 101.304-55.69 171.042-19.107 69.738 36.584 106.227 104.451 81.501 151.586-21.264 40.536-76.784 44.151-132.61 14.866-1.538-.807-4.033-2.103-6.857-3.567L150.768 502.471c-3.632 6.924-8.488 9.538-14.032 9.529zm-30.582-67.835l-3.144-1.649-.7-.366-42.546-22.32v-.001l-10.256-5.38c-1.738-.911-2.407-3.057-1.496-4.794l13.465-25.667c.906-1.728 3.036-2.399 4.768-1.509l.028.013 20.513 10.761c1.736.911 3.883.241 4.794-1.496l13.466-25.667c.911-1.737.24-3.883-1.497-4.794l-10.256-5.382-10.256-5.38c-1.737-.911-2.406-3.057-1.495-4.794l13.464-25.669c.911-1.737 3.058-2.406 4.794-1.494l10.258 5.38 26.697 14.005 16.548 8.681c.007.003.014.007.021.011l3.125 1.639-14.142 26.957-.973 1.855c0 .001-.001.003-.002.004l-20.063 38.245-2.041 3.888-11.424 21.779c-.002.004-.005.009-.008.014zm67.232-128.162l-3.145-1.651-14.938-7.837-11.794-6.187c-1.737-.911-2.408-3.057-1.497-4.794l13.466-25.667c.911-1.737 3.058-2.408 4.794-1.497l11.795 6.188 14.939 7.837c.007.003.014.007.021.01l3.125 1.64-1.651 3.145-6.731 12.834-6.733 12.833c-.003.005-.006.008-.009.013zm219.778-151.914c8.857.016 15.784-3.552 20.386-12.326 14.027-26.737-11.92-67.987-57.953-92.135-46.032-24.148-94.719-22.049-108.746 4.688-14.026 26.737 24.987 44.293 71.02 68.441 30.928 16.224 57.156 31.296 75.293 31.332z"/></svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1007 KiB

After

Width:  |  Height:  |  Size: 1013 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 947 KiB

After

Width:  |  Height:  |  Size: 960 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1020 KiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 315 KiB

After

Width:  |  Height:  |  Size: 322 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 405 KiB

After

Width:  |  Height:  |  Size: 408 KiB

+81 -37
View File
@@ -1,40 +1,84 @@
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>KeeWeb</title>
<meta name="application-name" content="KeeWeb">
<meta name="kw-signature" content="">
<meta name="kw-config" content="(no-config)">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="KeeWeb">
<meta name="theme-color" content="#6386ec">
<meta name="msapplication-config" content="browserconfig.xml">
<meta name="msapplication-TileColor" content="#6386ec">
<link rel="apple-touch-icon" sizes="180x180" href="icons/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="icons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="icons/favicon-16x16.png">
<link rel="mask-icon" href="icons/safari-pinned-tab.svg" color="#6386ec">
<link rel="apple-touch-startup-image" href="icons/splash-640x1136.png" media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="icons/splash-750x1294.png" media="(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="icons/splash-1242x2148.png" media="(device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="icons/splash-1125x2436.png" media="(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="icons/splash-1536x2048.png" media="(min-device-width: 768px) and (max-device-width: 1024px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="icons/splash-1668x2224.png" media="(min-device-width: 834px) and (max-device-width: 834px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: portrait)">
<link rel="apple-touch-startup-image" href="icons/splash-2048x2732.png" media="(min-device-width: 1024px) and (max-device-width: 1024px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: portrait)">
<link rel="manifest" href="manifest.json">
<link rel="stylesheet" href="css/main.css?__inline=true" />
<script src="js/vendor.js?__inline=true"></script>
<script src="js/app.js?__inline=true"></script>
<script src="js/runtime.js?__inline=true"></script>
</head>
<body class="th-d">
<noscript>
<h1>KeeWeb</h1>
<p>KeeWeb is a password manager written in JavaScript. Please enable JavaScript to run it.</p>
</noscript>
</body>
<head lang="en">
<meta charset="UTF-8" />
<title>KeeWeb</title>
<meta
http-equiv="Content-Security-Policy"
content="
default-src 'self';
font-src data:;
script-src 'self' 'unsafe-eval';
style-src 'self' blob:;
connect-src 'self' ws: https:;
child-src 'self' blob:;
worker-src 'self' blob:;
img-src 'self' data: blob: https://services.keeweb.info/;
object-src 'none';
form-action 'none';
"
/>
<meta name="application-name" content="KeeWeb" />
<meta name="kw-config" content="(no-config)" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="apple-mobile-web-app-title" content="KeeWeb" />
<meta name="theme-color" content="#6386ec" />
<meta name="msapplication-config" content="browserconfig.xml" />
<meta name="msapplication-TileColor" content="#6386ec" />
<link rel="apple-touch-icon" sizes="180x180" href="icons/apple-touch-icon.png" />
<link rel="icon" type="image/png" sizes="32x32" href="icons/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="icons/favicon-16x16.png" />
<link rel="mask-icon" href="icons/safari-pinned-tab.svg" color="#6386ec" />
<link
rel="apple-touch-startup-image"
href="icons/splash-640x1136.png"
media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)"
/>
<link
rel="apple-touch-startup-image"
href="icons/splash-750x1294.png"
media="(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)"
/>
<link
rel="apple-touch-startup-image"
href="icons/splash-1242x2148.png"
media="(device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)"
/>
<link
rel="apple-touch-startup-image"
href="icons/splash-1125x2436.png"
media="(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)"
/>
<link
rel="apple-touch-startup-image"
href="icons/splash-1536x2048.png"
media="(min-device-width: 768px) and (max-device-width: 1024px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: portrait)"
/>
<link
rel="apple-touch-startup-image"
href="icons/splash-1668x2224.png"
media="(min-device-width: 834px) and (max-device-width: 834px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: portrait)"
/>
<link
rel="apple-touch-startup-image"
href="icons/splash-2048x2732.png"
media="(min-device-width: 1024px) and (max-device-width: 1024px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: portrait)"
/>
<link rel="manifest" href="manifest.json" />
<link rel="stylesheet" href="css/app.css?__inline=true" />
<script src="js/app.js?__inline=true"></script>
</head>
<body class="th-dark">
<div class="app">
<noscript>
<h1>KeeWeb</h1>
<p>KeeWeb is a password manager written in JavaScript. Please enable JavaScript to run it.</p>
</noscript>
</div>
</body>
</html>
+71
View File
@@ -0,0 +1,71 @@
(function (global) {
var babelHelpers = global.babelHelpers = {};
babelHelpers.typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
return typeof obj;
} : function (obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
babelHelpers.defineProperty = function (obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
};
babelHelpers.slicedToArray = function () {
function sliceIterator(arr, i) {
var _arr = [];
var _n = true;
var _d = false;
var _e = undefined;
try {
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
_arr.push(_s.value);
if (i && _arr.length === i) break;
}
} catch (err) {
_d = true;
_e = err;
} finally {
try {
if (!_n && _i["return"]) _i["return"]();
} finally {
if (_d) throw _e;
}
}
return _arr;
}
return function (arr, i) {
if (Array.isArray(arr)) {
return arr;
} else if (Symbol.iterator in Object(arr)) {
return sliceIterator(arr, i);
} else {
throw new TypeError("Invalid attempt to destructure non-iterable instance");
}
};
}();
babelHelpers.toConsumableArray = function (arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
return arr2;
} else {
return Array.from(arr);
}
};
})(typeof global === "undefined" ? self : global);
@@ -1,9 +1,4 @@
{
"months": ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
"monthsShort": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
"weekdays": ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
"weekdaysShort": ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
"retToApp": "return to app",
"name": "name",
"icon": "icon",
@@ -19,6 +14,7 @@
"or": "or",
"history": "history",
"template": "template",
"templates": "templates",
"notImplemented": "Not Implemented",
"saveChanges": "Save changes",
"discardChanges": "Discard changes",
@@ -27,27 +23,57 @@
"help": "Help",
"settings": "Settings",
"plugins": "Plugins",
"rank": "rank",
"ctrlKey": "ctrl",
"shiftKey": "shift",
"altKey": "alt",
"error": "error",
"oneMinute": "one minute",
"minutes": "{} minutes",
"oneHour": "one hour",
"hours": "{} hours",
"oneDay": "one day",
"days": "{} days",
"oneWeek": "one week",
"oneMonth": "one month",
"oneYear": "one year",
"cache": "cache",
"file": "file",
"device": "device",
"webdav": "WebDAV",
"dropbox": "Dropbox",
"gdrive": "Google Drive",
"onedrive": "OneDrive",
"menuAllItems": "All Items",
"menuColors": "Colors",
"menuTrash": "Trash",
"menuSetGeneral": "General",
"menuSetBrowser": "Browser",
"menuSetAbout": "About",
"menuSetDevices": "Devices",
"menuAlertNoTags": "No tags",
"menuAlertNoTagsBody": "You can add new tags while editing fields, in tags section.",
"menuAlertNoTagsBody": "You can add new tags while editing fields, in the Tags section.",
"menuEmptyTrash": "Empty Trash",
"menuEmptyTrashAlert": "Empty Trash?",
"menuEmptyTrashAlertBody": "You will not be able to put items back",
"menuItemCollapsed": "Double-click to expand",
"menuRestoreApp": "Open {}",
"menuQuitApp": "Quit {}",
"sysMenuAboutKeeWeb": "About {}",
"sysMenuServices": "Services",
"sysMenuHide": "Hide {}",
"sysMenuHideOthers": "Hide Others",
"sysMenuUnhide": "Show All",
"sysMenuQuit": "Quit {}",
"sysMenuEdit": "Edit",
"sysMenuUndo": "Undo",
"sysMenuRedo": "Redo",
"sysMenuCut": "Cut",
"sysMenuCopy": "Copy",
"sysMenuPaste": "Paste",
"sysMenuSelectAll": "Select All",
"sysMenuWindow": "Window",
"sysMenuMinimize": "Minimize",
"sysMenuClose": "Close Window",
"alertYes": "Yes",
"alertNo": "No",
"alertOk": "OK",
@@ -56,14 +82,13 @@
"alertCopy": "Copy",
"alertClose": "Close",
"alertDoNotAsk": "Don't ask me anymore",
"alertAllow": "Allow",
"alertDeny": "Deny",
"appBeta": "WARNING: beta version, only for preview",
"footerOpen": "Open / New",
"footerSyncError": "Sync error",
"footerTitleGen": "Generate",
"footerTitleLock": "Lock",
"genLen": "Length",
"genNewPass": "New password",
"genPresetDefault": "default preset",
@@ -75,14 +100,14 @@
"genPresetMac": "MAC address",
"genPresetHash128": "128-bit hash",
"genPresetHash256": "256-bit hash",
"genHidePass": "Hide password",
"genShowPass": "Show password",
"grpTitle": "Group",
"grpSearch": "Enable searching entries in this group",
"grpAutoType": "Enable auto-type",
"grpAutoTypeSeq": "Auto-type sequence",
"grpAutoTypeSeqDefault": "Use default auto-type sequence",
"grpTrash": "Delete group with all entries",
"tagTitle": "Tag",
"tagTrash": "Remove tag from all entries",
"tagRename": "Rename",
@@ -92,7 +117,6 @@
"tagExistsBody": "Tag with this name already exists. Please choose another name.",
"tagBadName": "Bad name",
"tagBadNameBody": "Tag name cannot contain characters {}. Please remove them.",
"genPsTitle": "Generator Presets",
"genPsCreate": "New preset",
"genPsDelete": "Delete preset",
@@ -109,17 +133,19 @@
"genPsAmbiguous": "Ambiguous symbols",
"genPsInclude": "Additional symbols to include",
"genPsExample": "Example of generated password",
"genPsPattern": "Pattern",
"genPsPatternHelp": "Patterns can be used to specify custom rules for selecting characters. For example, 1-AA will generate passwords starting with a digit, followed by a dash and two letters. You can use these symbols:",
"genPsAllRanges": "All symbols",
"genPsIncluded": "Additional symbols added above",
"keyChangeTitleRemote": "Master Key Changed",
"keyChangeMessageRemote": "Master key was changed for this database. Please enter a new key",
"keyChangeTitleExpired": "Master Key Expired",
"keyChangeMessageExpired": "Master key for this database is expired. Please enter a new key",
"keyChangeRepeatPassword": "Password, once again",
"keyEnter": "Enter",
"keyEsc": "Esc",
"iconFavTitle": "Download and use website favicon",
"iconSelCustom": "Select custom icon",
"iconSelCustom": "Select a custom icon",
"listEmptyTitle": "Empty",
"listEmptyAdd": "add with {} button above",
"listGroup": "Group",
@@ -129,7 +155,6 @@
"listAddTemplateHeader": "Templates",
"listAddTemplateBody1": "Templates allow you to create entries with one click. Add something to template entry and then click {} again to use this template.",
"listAddTemplateBody2": "You can always find your templates in {} group.",
"searchAddNew": "Add New",
"searchSort": "Sort",
"searchCreated": "Created",
@@ -147,12 +172,14 @@
"searchOptions": "Options",
"searchCase": "Match case",
"searchRegex": "RegEx",
"searchRank": "Rank",
"searchRank": "Auto",
"searchExact": "Exact",
"openOpen": "Open",
"openNew": "New",
"openNewFile": "New",
"openMore": "More",
"openDemo": "Demo",
"openGenerate": "Generate",
"openXml": "Import XML",
"openCaps": "Caps Lock is on",
"openClickToOpen": "Click to open a file",
@@ -187,12 +214,19 @@
"openConfigErrorNotFound": "File not found",
"openError": "Error",
"openErrorDescription": "There was an error opening file",
"openErrorDescriptionMaybeTouchIdChanged": "The error looks similar to what usually happens when Touch ID setup is changed, for example, you added or removed an additional finger. If it's the case, go to Settings, disable Touch ID, and re-enable it again.",
"openErrorFileNotFound": "File not found",
"openListErrorBody": "There was an error loading file list",
"openShowAllFiles": "Show all files",
"detAttDownload": "Shift-click attachment button to download or",
"openFileNoCacheError": "File not found in the cache storage. This can happen because browser storage was cleaned up. To open the file, remove it from KeeWeb and add it again.",
"openChalRespHeader": "Challenge-Response",
"openChalRespLoading": "Loading the list of YubiKeys",
"openChalRespSelectYubiKey": "Select a YubiKey that you would like to use",
"openChalRespErrorEmpty": "No YubiKeys found.",
"openChalRespErrorEmptyMac": "First time using this feature on macOS? KeeWeb must be added to the Input Monitoring section of security settings.",
"detAttDownload": "Shift-click the attachment button to download it or",
"detAttDelToRemove": "Delete to remove",
"detAttSave": "Save as …",
"detEmpty": "Your passwords will be displayed here",
"detGroupRestore": "To restore this group, please drag it to any group outside trash",
"detHistoryClickPoint": "Click entry history timeline point to view state",
@@ -212,8 +246,8 @@
"detHistoryRevertAlertBody": "Your current state will be saved to history.",
"detHistoryDeleteAlert": "Delete this history state?",
"detHistoryDeleteAlertBody": "You will not be able to restore it.",
"detHistoryDiscardChangesAlert": "Discard changed made to entry?",
"detHistoryDiscardChangesAlertBody": "Unsaved changed will be lost, there will be no way back.",
"detHistoryDiscardChangesAlert": "Discard changes made to entry?",
"detHistoryDiscardChangesAlertBody": "Unsaved changes will be lost, there will be no way back.",
"detBackToList": "back to list",
"detSetIconColor": "Change color",
"detSetIcon": "Change icon",
@@ -230,19 +264,24 @@
"detDelFromTrash": "Delete from trash?",
"detDelFromTrashBody": "You will not be able to put it back.",
"detDelFromTrashBodyHint": "To quickly remove all items from trash, click Empty icon in Trash menu.",
"detDelToTrash": "Delete the entry?",
"detDelToTrashBody": "The entry will be moved to the trash folder.",
"detFieldCopied": "Copied",
"detFieldCopiedTime": "Copied for {} seconds",
"detCopyHint": "You can copy field value with click on its title",
"detCopyHint": "You can copy field value by clicking its title",
"detMore": "more",
"detClickToAddField": "click to add a new field",
"detMenuAddNewField": "Add new field",
"detMenuAddNewField": "Add a new field",
"detMenuAddNewWebsite": "Add another website",
"detMenuShowEmpty": "Show empty fields",
"detMenuHideEmpty": "Hide empty fields",
"detMenuAddField": "Add {}",
"detMenuCopyPassword": "Copy password",
"detMenuCopyUser": "Copy user",
"detSetupOtp": "One-time passwords",
"detMenuCopyOtp": "Copy one-time code",
"detSetupOtp": "One-time codes",
"detClone": "Make a copy",
"detCopyEntryToClipboard": "Copy all fields",
"detClonedName": "Copy",
"detAutoType": "Auto-type",
"detAutoTypeSettings": "Auto-type settings",
@@ -269,17 +308,34 @@
"detOtpQrError": "QR code scan error",
"detOtpQrErrorBody": "Sorry, we could not read the QR code, please try once again or contact the app authors with error details.",
"detOtpQrWrong": "Wrong QR code",
"detOtpQrWrongBody": "Your QR code was successfully scanned but it doesn't contain one-time password data.",
"detOtpQrWrongBody": "Your QR code was successfully scanned but it doesn't contain one-time code data.",
"detOtpField": "One-time code",
"detOtpClickToTouch": "Click to generate",
"detOtpGenerating": "Generating...",
"detOtpTouch": "Touch your {}",
"detLockField": "Lock this field, so its content isn't searchable and visible. Displaying the content requires explicitly clicking it.",
"detUnlockField": "Unlock this field, making its content searchable and visible immediately",
"detRevealField": "Reveal",
"detHideField": "Hide",
"detAutoTypeField": "Auto type",
"detIssuesHideTooltip": "Hide this warning",
"detIssueWeakPassword": "The password is weak, it's recommended to change it.",
"detIssuePoorPassword": "The password is very weak, it's strongly recommended to change it.",
"detIssuePwnedPassword": "This password has been exposed in a data breach according to {}, it's recommended to change it.",
"detIssuePasswordCheckError": "There was an error checking password strength online.",
"detIssueOldPassword": "The password is old.",
"detIssueCloseAlertHeader": "Hide password issues",
"detIssueCloseAlertBody": "There are different ways you can hide this warning:",
"detIssueCloseAlertEntry": "Don't show for this entry",
"detIssueCloseAlertSettings": "Adjust global settings",
"autoTypeEntryFields": "Entry fields",
"autoTypeModifiers": "Modifier keys",
"autoTypeKeys": "Keys",
"autoTypeLink": "more...",
"autoTypeError": "Auto-type error",
"autoTypeErrorGeneric": "There was an error performing auto-type: {}",
"autoTypeErrorGlobal": "To use system-wide shortcut, please focus the app where you want to type your password",
"autoTypeErrorAccessibilityMacOS": "We tried to send keystrokes to the application, but it doesn't seem to work. This may happen because of missing permissions, click here to read more about it:",
"autoTypeErrorGlobal": "To use a system-wide shortcut, please focus the app where you want to type your password",
"autoTypeErrorNotInstalled": "{} is not installed",
"autoTypeHeader": "Auto-Type: Select",
"autoTypeMsgNoWindow": "We were unable to get active window title, start typing to search",
@@ -288,7 +344,9 @@
"autoTypeSelectionHint": "Type the autotype sequence",
"autoTypeSelectionHintAction": "Only type the password",
"autoTypeSelectionHintOpt": "Only type the username",
"autoTypeSelectionHintShift": "Other fields",
"autoTypeSelectionOtp": "One-time code",
"autoTypeUnlockMessage": "Unlock to auto-type",
"appSecWarn": "Not Secure!",
"appSecWarnBody1": "You have loaded this app with an insecure connection. Someone may be watching you and stealing your passwords. We strongly advise you to stop, unless you clearly understand what you're doing.",
"appSecWarnBody2": "Yes, your database is encrypted but no one can guarantee that the app has not been modified on the way to you.",
@@ -302,6 +360,8 @@
"appSaveError": "Save Error",
"appSaveErrorBody": "Failed to auto-save file",
"appSaveErrorBodyMul": "Failed to auto-save files:",
"appSaveErrorExitLoseChanges": "Quit and lose all changes",
"appSaveErrorExitLoseChangesBody": "You can either quit the app and lose all changes, or go file settings to export data",
"appSettingsError": "Error loading app",
"appSettingsErrorBody": "There was an error loading app settings. Please double check the app URL or contact your administrator.",
"appNotSupportedError": "Your browser doesn't support some important features we're using.",
@@ -310,7 +370,7 @@
"appRightsAlert": "Locking KeeWeb app",
"appRightsAlertBody1": "Your KeeWeb app is currently not guarded against unauthorized changes. We're asking you for permissions to make the app writable only for administrators.",
"appRightsAlertBody2": "Don't want to give permissions? You can do it yourself in Terminal",
"appBrowserAuthComplete": "Authentication is complete, you may close this tab now.",
"setGenTitle": "General Settings",
"setGenUpdate": "Update",
"setGenNewVersion": "New app version was released and downloaded",
@@ -333,17 +393,30 @@
"setGenExtractingUpdate": "Extracting update...",
"setGenCheckErr": "There was an error downloading new version",
"setGenNeverChecked": "Never checked for updates",
"setGenRestartToUpdate": "Restart the app to update",
"setGenRestartToUpdate": "Restart KeeWeb to update",
"setGenDownloadAndRestart": "Download update and restart",
"setGenAppearance": "Appearance",
"setGenTheme": "Theme",
"setGenThemeFb": "Flat blue",
"setGenThemeDefault": "Default",
"setGenThemeDark": "Dark",
"setGenThemeLight": "Light",
"setGenThemeBlue": "Flat blue",
"setGenThemeFb": "Dark blue",
"setGenThemeBl": "Light blue",
"setGenThemeBrown": "Brownie",
"setGenThemeDb": "Dark brown",
"setGenThemeWh": "White",
"setGenThemeLb": "Light brown",
"setGenThemeTerminal": "Terminal",
"setGenThemeTe": "Terminal",
"setGenThemeLt": "Terminal light",
"setGenThemeHighContrast": "High contrast",
"setGenThemeHc": "High contrast",
"setGenThemeDc": "Dark contrast",
"setGenThemeSol": "Solarized",
"setGenThemeSd": "Solarized dark",
"setGenThemeSl": "Solarized light",
"setGenMoreThemes": "More themes",
"setGenAutoSwitchTheme": "Automatically switch between light and dark theme when possible",
"setGenLocale": "Language",
"setGenLocOther": "other languages are available as plugins",
"setGenFontSize": "Font size",
@@ -356,12 +429,16 @@
"setGenTitlebarStyleHiddenInset": "Custom title, draggable window",
"setGenShowSubgroups": "Show entries from all subgroups",
"setGenTableView": "Entries list table view",
"setGenColorfulIcons": "Colorful custom icons in list",
"setGenDirectAutotype": "If only one matching entry is found, select that one automatically for Autotype",
"setGenColorfulIcons": "Colorful custom icons in the list",
"setGenUseMarkdown": "Markdown in notes",
"setGenUseGroupIconForEntries": "Automatically use group icon for new entries",
"setGenDirectAutotype": "If only one matching entry is found, select that one automatically for auto-type",
"setGenAutoTypeTitleFilterEnabled": "Filter entries by title in auto-type",
"setGenFunction": "Function",
"setGenAutoSyncOnClose": "Automatically save and sync on close",
"setGenAutoSyncTimer": "Automatically save and sync periodically",
"setGenAutoSyncTimerOff": "Disabled",
"setGenAutoSyncTimerOnChange": "On every change",
"setGenAutoSyncTimerInterval": "Every {} minute(s)",
"setGenRememberKeyFiles": "Remember key files",
"setGenNoRememberKeyFiles": "Don't remember",
@@ -377,13 +454,17 @@
"setGenNoClear": "Don't clear",
"setGenClearSeconds": "In {} seconds",
"setGenClearMinute": "In a minute",
"setGenMinInstead": "Minimize app instead of close",
"setGenMinInstead": "Minimize the app instead of close",
"setGenMinOnFieldCopy": "Minimize on field copy",
"setGenLock": "Auto lock",
"setGenLockMinimize": "When the app is minimized",
"setGenLockCopy": "On password copy",
"setGenLockAutoType": "On auto-type",
"setGenLockOrSleep": "When the computer is locked or put to sleep",
"setGenStorage": "Storage",
"setGenDisableOfflineStorage": "Don't cache loaded files in offline storage",
"setGenShortLivedStorageToken": "Use short-lived sessions in cloud storage providers",
"setGenStorageLogout": "Log out",
"setGenShowAdvanced": "Show advanced settings",
"setGenDevTools": "Show dev tools",
"setGenTryBeta": "Try beta version until restart",
@@ -391,18 +472,35 @@
"setGenTryBetaWarningBody": "Please save all files and click this button again",
"setGenShowAppLogs": "Show app logs",
"setGenReloadApp": "Reload the app",
"setGenFieldLabelDblClickAutoType": "Auto-type on double-clicking field labels",
"setGenTouchId": "Touch ID",
"setGenTouchIdDisabled": "Don't use Touch ID",
"setGenTouchIdMemory": "Unlock with Touch ID only while KeeWeb is running",
"setGenTouchIdFile": "Always use Touch ID instead of master password",
"setGenTouchIdPass": "Require master password after",
"setGenAudit": "Audit",
"setGenAuditPasswords": "Show warnings about password strength",
"setGenAuditPasswordEntropy": "Check password length and randomness",
"setGenExcludePinsFromAudit": "Never check short numeric PIN codes, such as 123456",
"setGenCheckPasswordsOnHIBP": "Check passwords using an online service {}",
"setGenHelpHIBP": "KeeWeb can check if your passwords have been previously exposed in a data breach using an online service. Your password cannot be recovered based on data sent online, however, the number of passwords checked this way may be exposed. More about your privacy when using this service can be found {}. If this option is enabled, KeeWeb will automatically check your passwords there.",
"setGenHelpHIBPLink": "here",
"setGenAuditPasswordAge": "Old passwords",
"setGenAuditPasswordAgeOff": "Don't show warnings about old passwords",
"setGenAuditPasswordAgeOneYear": "Show warnings for passwords older than one year",
"setGenAuditPasswordAgeYears": "Show warnings for passwords older than {} years",
"setFilePath": "File path",
"setFileStorage": "This file is loaded from {}.",
"setFileIntl": "This file is stored in the internal app storage",
"setFileLocalHint": "Want to work seamlessly with local files?",
"setFileDownloadApp": "Download a desktop app",
"setFileSave": "Save",
"setFileSaveTo": "Save to ...",
"setFileSaveTo": "Save to …",
"setFileClose": "Close",
"setFileSync": "Sync",
"setFileSyncVerb": "Sync",
"setFileSaveToXml": "XML",
"setFileSaveToHtml": "HTML",
"setFileLastSync": "Last sync",
"setFileLastSyncUnknown": "unknown",
"setFileSyncInProgress": "sync in progress",
@@ -417,6 +515,10 @@
"setFileNames": "Names",
"setFileDefUser": "Default user",
"setFileEnableTrash": "Enable trash",
"setFileHistMode": "Entry history",
"setFileHistLimited": "Delete old history records automatically",
"setFileHistDisabled": "Don't save history",
"setFileHistUnlimited": "Keep history records forever",
"setFileHistLen": "History length, keep last records per entry",
"setFileHistSize": "History size, total MB per file",
"setFileBackups": "Backups",
@@ -441,10 +543,10 @@
"setFileKdfParamsPar": "Parallelism",
"setFileKeyChangeForce": "Ask to change key after (days)",
"setFileUseKeyFile": "Use key file",
"setFileUseGenKeyFile": "Use generated key file",
"setFileUseOldKeyFile": "Use old key file",
"setFileGenKeyFile": "Generate new key file",
"setFileDontUseKeyFile": "Don't use key file",
"setFileUseGenKeyFile": "Use the generated key file",
"setFileUseOldKeyFile": "Use the old key file",
"setFileGenKeyFile": "Generate a new key file",
"setFileDontUseKeyFile": "Don't use a key file",
"setFileEmptyPass": "Empty password",
"setFileEmptyPassBody": "Saving database with an empty password makes it completely unprotected. Do you really want to do it?",
"setFileSaveError": "Save error",
@@ -455,7 +557,17 @@
"setFileUnsavedBody": "There are unsaved changes in this file",
"setFileCloseNoSave": "Close and lose changes",
"setFileDontClose": "Don't close",
"setFileFormatVersion": "File format",
"setFileExportRaw": "Exporting your passwords",
"setFileExportRawBody": "The exported file will contain your passwords, they will not be encrypted there. Would you like to proceed?",
"setFileDeviceIntro": "One-time codes from this {} will be displayed in the app.",
"setFileDeviceSettings": "Settings",
"setFileYubiKey": "YubiKey",
"setFileDontUseYubiKey": "Don't use a YubiKey",
"setFileRefreshYubiKeyList": "Refresh the list",
"setFileYubiKeyHeader": "YubiKey",
"setFileYubiKeyBody": "Using a YubiKey as a part of master key is dangerous and you may lose access to your passwords if something goes wrong. Have you made a backup of your file before changing this setting?",
"setFileYubiKeyErrorEmptyMac": "Looks like there's a YubiKey plugged in, but it's not visible. KeeWeb must be added to the Input Monitoring section of security settings to access YubiKeys.",
"setShTitle": "Shortcuts",
"setShShowAll": "show all items",
"setShColors": "show items with colors",
@@ -473,12 +585,14 @@
"setShSave": "save all files",
"setShGen": "generate password",
"setShSet": "app settings",
"setShCopyPassGlobal": "copy password (when the app is in background)",
"setShCopyUserGlobal": "copy user (when the app is in background)",
"setShCopyUrlGlobal": "copy website (when the app is in background)",
"setShAutoTypeGlobal": "auto-type (when the app is in background)",
"setShCopyPassGlobal": "copy password",
"setShCopyOtp": "copy OTP",
"setShAutoTypeGlobal": "auto-type",
"setShCopyPassOnly": "copy password",
"setShRestoreApp": "open {}",
"setShGlobal": "These system-wide shortcuts work when the app is running in background. You can click them to select your own shortcut.",
"setShLock": "lock database",
"setShEdit": "Press a new key combination to set it as shortcut",
"setPlInstallTitle": "Install new plugins",
"setPlInstallDesc": "KeeWeb plugins add features, themes, and languages to KeeWeb. Plugins run with the same privileges as KeeWeb, they can access and manage all your passwords. Never install plugins you don't trust.",
"setPlInstallLabel": "Plugin URL",
@@ -509,32 +623,84 @@
"setPlTranslateLink": "translate the app to your language",
"setPlAutoUpdate": "Update automatically",
"setPlLoadGallery": "Load plugin gallery",
"setBrowserTitle": "Browser",
"setBrowserIntroDesktop": "KeeWeb can enter passwords using auto-type, however, a browser extension may be a more convenient way of doing it. KeeWeb supports two browser extensions:",
"setBrowserIntroKeeWebConnect": "the official KeeWeb extension, it's built with features of KeeWeb in mind, but you may miss some advanced capabilities that can be found in the other extension.",
"setBrowserIntroKeePassXcBrowser": "this extension was developed for KeePassXC, it's been on the market for a while and it is quite solid. The extension is not a part of KeeWeb and there may be compatibility issues.",
"setBrowserIntroWeb": "Install our browser extension to auto-fill passwords from KeeWeb on different pages. The browser extension will connect to a KeeWeb tab in your browser to fetch passwords. Click here to download the extension:",
"setBrowserNotEnabled": "Browser integration is not enabled, extensions won't be able to connect to KeeWeb. Use the checkboxes below to enable it:",
"setBrowserEnablePerBrowser": "Enable browser integration using the checkboxes below:",
"setBrowserFocusIfLocked": "Open KeeWeb if a browser extension tries to connect while there's no open file",
"setBrowserFocusIfEmpty": "Show the entry selection screen if there's no match found by URL",
"setBrowserOtherBrowsers": "Other browsers",
"setBrowserExtensionFor": "for {}",
"setBrowserExtensionNotSupported": "Not supported",
"setBrowserExtensionHelp": "How to install?",
"setBrowserExtensionInstall": "Install the extension",
"setBrowserExtensionKPXCWarnHeader": "{} will stop working",
"setBrowserExtensionKPXCWarnBody1": "Unfortunately it's not possible to connect one extension to several apps. If you connect the extension to KeeWeb, we'll overwrite its app association, which means that integration with {} will stop working. Even if you uncheck this checkbox, the association with {} won't be restored. To make it work again, configure browser integration in {} settings.",
"setBrowserExtensionKPXCWarnBody2": "Configure the extension to use KeeWeb?",
"setBrowserSessions": "Sessions",
"setBrowserSessionsEmpty": "No connected sessions.",
"setBrowserSessionsIntro": "These extensions are now connected to KeeWeb.",
"setBrowserSessionsActiveTooltip": "Active session",
"setBrowserSessionsActiveText": "This session is active. It can exchange data with KeeWeb based on the following permissions:",
"setBrowserSessionsInactiveTooltip": "Inactive session",
"setBrowserSessionsInactiveText": "This session is inactive. The extension is connected to KeeWeb, however, it hasn't tried to exchange data. When the extension requests anything, you will be able to choose what you want to share.",
"setBrowserSessionsDeniedTooltip": "Access denied",
"setBrowserSessionsDeniedText": "This session is inactive. The extension is connected to KeeWeb, however, you denied access to data.",
"setBrowserSessionsConnectedDate": "Connected",
"setBrowserSessionsTerminate": "Terminate this session",
"setBrowserSessionsAccessToFiles": "Allow access to files",
"setBrowserSessionsNoFileAccess": "The extension doesn't have access to any file, it won't be able to fetch passwords from KeeWeb.",
"setBrowserSessionsPasswordsRead": "Passwords read",
"setBrowserSessionsPasswordsWritten": "Passwords saved",
"setDevicesTitle": "Devices",
"setDevicesEnableUsb": "Enable interaction with USB devices",
"setDevicesYubiKeyIntro": "It's recommended to read {} before using a YubiKey.",
"setDevicesYubiKeyIntroLink": "this document",
"setDevicesYubiKeyToolsDesc": "To be able to use YubiKey in this mode, you need to install a tool called {}.",
"setDevicesYubiKeyToolsDesc2": "{} to get more information about this tool.",
"setDevicesYubiKeyToolsDescLink": "Click here",
"setDevicesYubiKeyToolsStatusChecking": "Checking if {} is installed",
"setDevicesYubiKeyToolsStatusOk": "{} is installed",
"setDevicesYubiKeyToolsStatusError": "{} is not installed or not working",
"setDevicesYubiKeyOtpTitle": "One-time codes",
"setDevicesYubiKeyOtpDesc": "YubiKey can be used to generate one-time codes for different services.",
"setDevicesYubiKeyOtpShowIcon": "Show the icon on the start screen",
"setDevicesYubiKeyOtpAutoOpen": "Automatically load one-time codes when there are open files",
"setDevicesYubiKeyOtpMatchEntries": "Show matching one-time codes in entries",
"setDevicesYubiKeyChalRespTitle": "Challenge-Response",
"setDevicesYubiKeyChalRespDesc": "It's also possible to use a YubiKey in challenge-response mode, so that a piece of private key used to encrypt files resides on a YubiKey.",
"setDevicesYubiKeyChalRespShow": "Show the option to use a YubiKey when opening files",
"setDevicesYubiKeyStuckWorkaround": "Reconnect the YubiKey if it seems to be stuck during loading",
"setDevicesYubiKeyRememberChalResp": "Remember challenge-response while the app is open",
"setAboutTitle": "About",
"setAboutBuilt": "This app is built with these awesome tools",
"setAboutLic": "License",
"setAboutLicComment": "The app itself and all included components which are not in public domain are licensed under MIT license",
"setAboutLicComment": "The app itself and all included components are licensed under MIT license, unless otherwise specified",
"setAboutFirst": "This is an open-source app created by {}",
"setAboutSecond": "and licensed under {}.",
"setAboutSource": "The source code and issues are on {}.",
"setHelpFormat": "File Format",
"setHelpFormatBody": "This is a port of {} app built with web technologies. It understands files in KeePass format (kdbx). You can create such files (password databases) either in KeePass or in this app. The file format is 100% compatible and should be understood by both apps.",
"setHelpProblems": "Need some help?",
"setHelpProblems1": "If something goes wrong, please {}",
"setHelpProblems2": "or {}",
"setHelpOpenIssue": "open an issue on GitHub",
"setHelpContactLink": "contact a developer directly",
"setHelpContactLink": "contact the developer directly",
"setHelpAppInfo": "App information",
"setHelpOtherPlatforms": "Other platforms",
"setHelpDesktopApps": "Desktop apps",
"setHelpWebApp": "Web app",
"setHelpUpdates": "Updates",
"setHelpTwitter": "App twitter",
"dropboxSetupDesc": "Some configuration is required to use Dropbox in a self-hosted app. Please create your own Dropbox app and fill in its key below.",
"dropboxAppKey": "Dropbox app key",
"dropboxAppKeyDesc": "Copy the key from your Dropbox app (Developer settings)",
"dropboxAppKeyHint": "your app key",
"dropboxAppSecret": "Dropbox app secret",
"dropboxAppSecretDesc": "The secret can be found next to the app key",
"dropboxFolder": "App folder",
"dropboxFolderDesc": "If your app is linked to entire Dropbox (not app folder), set the folder with your kdbx files here",
"dropboxFolderSettingsDesc": "Select any folder in your Dropbox where files will be stored (root folder by default)",
@@ -543,16 +709,70 @@
"dropboxLinkApp": "App folder (Apps/KeeWeb)",
"dropboxLinkFull": "Full Dropbox or any folder",
"dropboxLinkCustom": "Own Dropbox app",
"gdriveSharedWithMe": "Shared with me",
"gdriveSharedDrives": "Shared drives",
"webdavSaveMethod": "Save method",
"webdavSaveMove": "Upload a temporary file and move",
"webdavSavePut": "Overwrite kdbx file with PUT",
"webdavSavePut": "Overwrite the kdbx file with PUT",
"webdavNoLastModified": "Last-Modified HTTP header is absent",
"webdavStatReload": "Always reload the file instead of relying on Last-Modified HTTP header",
"launcherSave": "Save Passwords Database",
"launcherFileFilter": "KeePass files",
"authPopupRequired": "Pop-ups are blocked",
"authPopupRequiredBody": "Please allow pop-ups in your browser or try again."
"authPopupRequiredBody": "Please allow pop-ups in your browser or try again.",
"exportFileInfo": "File information",
"exportHtmlName": "Name",
"exportHtmlDate": "Export date",
"exportGenerator": "Software",
"exportDescription": "This file is generated with {}.",
"exportEntries": "Entries",
"importCsvTitle": "Import from CSV",
"importCsvRun": "Import",
"importIgnoreField": "Ignore",
"importTo": "Entries will be imported to",
"importNewFile": "New file",
"yubiKeyStuckError": "The YubiKey seems to be stuck, auto-repair can be enabled in app settings.",
"yubiKeyNoKeyHeader": "YubiKey required",
"yubiKeyNoKeyBody": "Please insert your YubiKey with serial number {}",
"yubiKeySlot": "slot",
"yubiKeyTouchRequestedHeader": "Touch your YubiKey",
"yubiKeyTouchRequestedBody": "Please touch your YubiKey with serial number {}",
"yubiKeyDisabledErrorHeader": "USB is disabled",
"yubiKeyDisabledErrorBody": "YubiKey is required to open this file, please enable USB devices in settings.",
"yubiKeyErrorWithCode": "YubiKey error, code {}.",
"bioOpenAuthPrompt": "open \"{}\"",
"extensionErrorNoOpenFiles": "No open files",
"extensionErrorUserRejected": "The request was denied",
"extensionErrorNoMatches": "No matching logins",
"extensionErrorAlertDisplayed": "Cannot ask a question now because there's another dialog displayed, please try again",
"extensionConnectHeader": "Extension data exchange",
"extensionConnectIntro": "A browser extension that identifies itself as {} tries to exchange data with KeeWeb.",
"extensionConnectUnknownActivity": "KeeWeb doesn't verify that the connected application is what it pretends to be. Approve the request only if you recognize this activity.",
"extensionConnectFiles": "In this session, allow access to:",
"extensionConnectAllOtherFiles": "All other files",
"extensionConnectAllFiles": "All files",
"extensionConnectAskGet": "Ask before returning passwords to the extension:",
"extensionConnectAskGetMultiple": "if there's more than one match",
"extensionConnectAskGetAlways": "always",
"extensionConnectAskSave": "Ask before saving new passwords to KeeWeb:",
"extensionConnectAskSaveAlways": "always",
"extensionConnectAskSaveAuto": "when it's not possible to save automatically",
"extensionConnectSettingsAreForSession": "Settings you select here are valid only for the active session. You can view and manage sessions in KeeWeb settings.",
"extensionUnlockMessage": "Unlock to connect a browser extension",
"extensionNewGroupHeader": "New group",
"extensionNewGroupBody": "{} is trying to create a new group. Allow this?",
"extensionNewGroupPath": "Group path",
"extensionNewGroupFile": "This group will be created in:",
"extensionSaveEntryHeader": "Save password",
"extensionSaveEntryBody": "{} is trying to save a password. Allow this?",
"extensionSaveEntryAuto": "Save other passwords automatically in this session",
"extensionSaveEntryNewGroup": "new group",
"extensionSelectPasswordFor": "Select a password for {}",
"selectEntryHeader": "Select entry",
"selectEntryEnterHint": "use the highlighted entry",
"selectEntryTypingHint": "Start typing to filter",
"selectEntryContains": "Contains text",
"selectEntrySubdomains": "Subdomains",
"selectEntryFieldHeader": "Select field",
"selectEntryFieldTouch": "Press the button on your device to generate a one-time code."
}
@@ -1,50 +1,4 @@
{
"months": [
"Januar",
"Februar",
"März",
"April",
"Mai",
"Juni",
"Juli",
"August",
"September",
"Oktober",
"November",
"Dezember"
],
"monthsShort": [
"Jan",
"Feb",
"Mär",
"Apr",
"Mai",
"Jun",
"Jul",
"Aug",
"Sep",
"Okt",
"Nov",
"Dez"
],
"weekdays": [
"Sonntag",
"Montag",
"Dienstag",
"Mittwoch",
"Donnerstag",
"Freitag",
"Samstag"
],
"weekdaysShort": [
"So",
"Mo",
"Di",
"Mi",
"Do",
"Fr",
"Sa"
],
"retToApp": "zurück zur App",
"name": "Name",
"icon": "Icon",
@@ -56,10 +10,11 @@
"notes": "Notizen",
"entry": "Eintrag",
"group": "Gruppe",
"noTitle": "Keinen Titel",
"noTitle": "Kein Titel",
"or": "oder",
"history": "Verlauf",
"template": "Template",
"template": "Vorlage",
"templates": "Vorlagen",
"notImplemented": "Nicht implementiert",
"saveChanges": "Änderungen speichern",
"discardChanges": "Änderungen verwerfen",
@@ -68,8 +23,22 @@
"help": "Hilfe",
"settings": "Einstellungen",
"plugins": "Plugins",
"ctrlKey": "Strg",
"shiftKey": "Umschalt",
"altKey": "Alt",
"error": "Fehler",
"oneMinute": "Eine Minute",
"minutes": "{} Minuten",
"oneHour": "Eine Stunde",
"hours": "{} Stunden",
"oneDay": "Ein Tag",
"days": "{} Tage",
"oneWeek": "Eine Woche",
"oneMonth": "Ein Monat",
"oneYear": "Ein Jahr",
"cache": "Cache",
"file": "Datei",
"device": "Gerät",
"webdav": "WebDAV",
"dropbox": "Dropbox",
"gdrive": "Google Drive",
@@ -79,12 +48,31 @@
"menuTrash": "Papierkorb",
"menuSetGeneral": "Allgemein",
"menuSetAbout": "Info",
"menuSetDevices": "Geräte",
"menuAlertNoTags": "Keine Tags",
"menuAlertNoTagsBody": "Neue Tags können durch das Bearbeiten von Einträgen (Abschnitt “Tags”) hinzugefügt werden.",
"menuEmptyTrash": "Leere Papierkorb",
"menuAlertNoTagsBody": "Neue Tags können durch das Bearbeiten von Einträgen (Abschnitt „Tags“) hinzugefügt werden.",
"menuEmptyTrash": "Papierkorb leeren",
"menuEmptyTrashAlert": "Papierkorb leeren?",
"menuEmptyTrashAlertBody": "Die Einträge können nicht wiederhergestellt werden",
"menuItemCollapsed": "Doppelklick zum Aufklappen",
"menuRestoreApp": "{} öffnen",
"menuQuitApp": "{} beenden",
"sysMenuAboutKeeWeb": "Über {}",
"sysMenuServices": "Dienste",
"sysMenuHide": "{} ausblenden",
"sysMenuHideOthers": "Andere ausblenden",
"sysMenuUnhide": "Alle anzeigen",
"sysMenuQuit": "{} beenden",
"sysMenuEdit": "Bearbeiten",
"sysMenuUndo": "Rückgängig",
"sysMenuRedo": "Wiederherstellen",
"sysMenuCut": "Ausschneiden",
"sysMenuCopy": "Kopieren",
"sysMenuPaste": "Einfügen",
"sysMenuSelectAll": "Alles auswählen",
"sysMenuWindow": "Fenster",
"sysMenuMinimize": "Minimieren",
"sysMenuClose": "Fenster schließen",
"alertYes": "Ja",
"alertNo": "Nein",
"alertOk": "OK",
@@ -101,19 +89,21 @@
"genLen": "Länge",
"genNewPass": "Neues Passwort",
"genPresetDefault": "Standardeinstellung",
"genPresetDerived": "unverändert",
"genPresetDerived": "Wie das alte Passwort",
"genPresetPronounceable": "aussprechbar",
"genPresetMed": "durchschnittlich lang",
"genPresetMed": "Durchschnittliche Länge",
"genPresetLong": "lang",
"genPresetPin4": "4-stellige PIN",
"genPresetMac": "MAC-Adresse",
"genPresetHash128": "128-Bit Hash",
"genPresetHash256": "256-Bit Hash",
"genPresetHash128": "128-Bit-Hash",
"genPresetHash256": "256-Bit-Hash",
"genHidePass": "Passwort ausblenden",
"genShowPass": "Passwort einblenden",
"grpTitle": "Gruppe",
"grpSearch": "Suche für Einträge in dieser Gruppe aktivieren",
"grpAutoType": "Auto-Type aktivieren",
"grpAutoTypeSeq": "Auto-Type Abfolge",
"grpAutoTypeSeqDefault": "Standard Auto-Type Abfolge verwenden",
"grpAutoTypeSeq": "Auto-Type-Sequenz",
"grpAutoTypeSeqDefault": "Standard-Auto-Type-Sequenz verwenden",
"grpTrash": "Gruppe und alle enthaltenen Einträge löschen",
"tagTitle": "Tag",
"tagTrash": "Diesen Tag von allen Einträgen entfernen",
@@ -121,14 +111,14 @@
"tagTrashQuestion": "Diesen Tag von allen Einträgen entfernen?",
"tagTrashQuestionBody": "Der Tag wird von allen Einträgen entfernt. Diese Aktion kann nicht rückgängig gemacht werden.",
"tagExists": "Tag existiert bereits",
"tagExistsBody": "Ein Tag mit diesem Namen ist bereits vorhanden. Bitte wählen Sie einen anderen Namen.",
"tagExistsBody": "Ein Tag mit diesem Namen ist bereits vorhanden. Bitte einen anderen Namen wählen.",
"tagBadName": "Ungültiger Name",
"tagBadNameBody": "Der Tag-Name darf nicht die folgenden Zeichen enthalten: {}. Bitte entfernen Sie sie.",
"tagBadNameBody": "Der Tag-Name darf folgende Zeichen nicht enthalten: {}. Bitte diese entfernen.",
"genPsTitle": "Generator-Voreinstellungen",
"genPsCreate": "Neue Voreinstellung",
"genPsDelete": "Voreinstellung löschen",
"genPsNew": "Voreinstellung",
"genPsEnabled": "In Voreinstellungs-Liste anzeigen",
"genPsEnabled": "In Voreinstellungsliste anzeigen",
"genPsDefault": "Standardmäßig ausgewählt",
"genPsDefaultLength": "Standardlänge",
"genPsUpper": "Lateinische Großbuchstaben",
@@ -140,13 +130,17 @@
"genPsAmbiguous": "Ähnliche Zeichen",
"genPsInclude": "Zusätzliche Symbole angeben",
"genPsExample": "Beispiel für ein generiertes Passwort",
"genPsPattern": "Muster",
"genPsPatternHelp": "Mit Mustern können eigene Regeln zur Auswahl von Zeichen festgelegt werden. Beispielsweise werden mit 1-AA Passwörter generiert, die mit einer Ziffer starten, gefolgt von einem Bindestrich und zwei Großbuchstaben. Folgende Symbole stehen zur Verfügung:",
"genPsAllRanges": "Alle Zeichen",
"genPsIncluded": "Zusätzliche oben hinzugefügte Zeichen",
"keyChangeTitleRemote": "Hauptschlüssel geändert",
"keyChangeMessageRemote": "Der Hauptschlüssel für diese Datenbank wurde geändert. Bitte geben Sie das neue Passwort ein.",
"keyChangeMessageRemote": "Der Hauptschlüssel für diese Datenbank wurde geändert. Bitte das neue Passwort eingeben.",
"keyChangeTitleExpired": "Hauptschlüssel abgelaufen",
"keyChangeMessageExpired": "Der Hauptschlüssel für diese Datenkbank ist abgelaufen. Bitte geben Sie einen neuen Schlüssel ein.",
"keyChangeRepeatPassword": "Passwort (Wiederholung)",
"keyEnter": "Enter",
"iconFavTitle": "Website-Icon herunterladen und verwenden",
"iconFavTitle": "Website-Symbol herunterladen und verwenden",
"iconSelCustom": "Eigenes Icon auswählen",
"listEmptyTitle": "Leer",
"listEmptyAdd": "Zum Anlegen neuer Einträge den obigen {} Button benutzen",
@@ -154,9 +148,9 @@
"listNoWebsite": "keine Website",
"listNoUser": "kein Benutzer",
"listNoAttachments": "keine Anhänge",
"listAddTemplateHeader": "Templates",
"listAddTemplateBody1": "Templates ermöglichen es, Einträge mit nur einem Klick zu erstellen. Fügen Sie etwas zum Template-Eintrag hinzu und klicken Sie auf {}, um dieses Template zu benutzen.",
"listAddTemplateBody2": "Sie können Ihre Templates in der Gruppe “{}” finden.",
"listAddTemplateHeader": "Vorlagen",
"listAddTemplateBody1": "Vorlagen ermöglichen es, Einträge mit nur einem Klick zu erstellen. Fügen Sie etwas zum Vorlage-Eintrag hinzu und klicken Sie auf {}, um diese Vorlage zu verwenden.",
"listAddTemplateBody2": "Sie können Ihre Vorlagen in der Gruppe “{}” finden.",
"searchAddNew": "Hinzufügen",
"searchSort": "Sortierung",
"searchCreated": "Erstelldatum",
@@ -174,27 +168,31 @@
"searchOptions": "Suchoptionen",
"searchCase": "Groß/klein",
"searchRegex": "RegEx",
"searchRank": "Automatisch",
"searchExact": "Exakt",
"openOpen": "Öffnen",
"openNew": "Neu",
"openNewFile": "Neu",
"openMore": "Mehr",
"openDemo": "Demo",
"openGenerate": "Generieren",
"openXml": "XML importieren",
"openCaps": "Feststelltaste ist aktiviert",
"openClickToOpen": "Hier klicken, um eine Datei zu öffnen",
"openKeyFile": "Schlüsseldatei",
"openKeyFileDropbox": "(von Dropbox)",
"openDropHere": "Dateien hier ablegen",
"openFailedRead": "Konnte die Datei nicht lesen",
"openFailedRead": "Datei konnte nicht gelesen werden",
"openNothingFound": "Nichts gefunden",
"openNothingFoundBody": "Es konnten keine kompatiblen Dateien gefunden werden.",
"openSelectFile": "Datei auswählen",
"openSelectFileBody": "Wählen Sie eine Datei zum Öffnen aus",
"openPassFor": "Passwort für",
"openRemoveLastQuestion": "Lokale Datei löschen?",
"openRemoveLastQuestionBody": "Die Datei, die Sie löschen möchten, ist nur innerhalb der App gespeichert. Möchten Sie sie unwiederbringlich löschen?",
"openRemoveLastQuestionBody": "Die Datei, die Sie löschen möchten, ist nur innerhalb der App gespeichert. Möchten Sie diese unwiederbringlich löschen?",
"openRemoveLastQuestionModBody": "Die Datei, die Sie löschen möchten, beinhaltet lokale Änderungen. Möchten Sie diese Änderungen verwerfen und die Datei löschen?",
"openLocalFile": "Lokale Datei",
"openLocalFileBody": "Sie sind dabei, eine Datei zu öffnen, die innerhalb der App gespeichert wird. Wenn Sie an dieser Datei Änderungen vornehmen, werden diese nicht im Dateisystem gespeichert. Um die Datei mit den Änderungen zu erhalten, können Sie sie aus den Einstellungen heraus exportieren.",
"openLocalFileBody": "Sie sind dabei, eine Datei zu öffnen, die innerhalb der App gespeichert wird. Wenn Sie an dieser Datei Änderungen vornehmen, werden diese nicht im Dateisystem gespeichert. Um die Datei mit den Änderungen zu erhalten, können Sie diese aus den Einstellungen heraus exportieren.",
"openLocalFileDontShow": "Nicht wieder anzeigen",
"openWrongFile": "Inkompatibles Dateiformat",
"openWrongFileBody": "Dieses Dateiformat ist nicht kompatibel. Die App unterstützt KeePass-Datenbanken im kdbx-Format.",
@@ -203,10 +201,10 @@
"openUrl": "URL",
"openUrlDesc": "https://server/pfad/datei.kdbx, oder einfach datei.kdbx",
"openUser": "Benutzername",
"openUserDesc": "WebDAV Server Benutzername (falls erforderlich)",
"openUserDesc": "WebDAV-Server-Benutzername (falls erforderlich)",
"openUserPlaceholder": "kein Benutzername",
"openPass": "Passwort",
"openPassDesc": "WebDAV Server-Passwort (nicht das KDBX-Datei-Passwort)",
"openPassDesc": "WebDAV-Server-Passwort (nicht das KDBX-Datei-Passwort)",
"openPassPlaceholder": "kein Passwort",
"openConfigError": "Fehler: {}",
"openConfigErrorNotFound": "Datei nicht gefunden",
@@ -215,11 +213,18 @@
"openErrorFileNotFound": "Datei nicht gefunden",
"openListErrorBody": "Dateien konnten nicht geladen werden",
"openShowAllFiles": "Alle Dateien anzeigen",
"openFileNoCacheError": "Die Datei wurde im Cache-Speicher nicht gefunden. Möglicherweise wurde Ihr Browser-Speicher geleert. Um die Datei zu öffnen, entfernen Sie sie aus KeeWeb und fügen Sie sie erneut hinzu",
"openChalRespHeader": "Challenge-Response",
"openChalRespLoading": "Liste mit YubiKeys wird geladen",
"openChalRespSelectYubiKey": "Wählen Sie den YubiKey aus, den Sie benutzen wollen",
"openChalRespErrorEmpty": "Keine YubiKeys gefunden.",
"openChalRespErrorEmptyMac": "Verwenden Sie dieses Feature zum ersten Mal auf MacOS? KeeWeb muss in Ihren Sicherheitseinstellung im Input-Monitoring-Abschnitt hinzugefügt werden.",
"detAttDownload": "Umschalttaste + Klick auf den Anhang-Button zum Herunterladen oder",
"detAttDelToRemove": "Backspace zum entfernen",
"detAttDelToRemove": "Backspace zum Entfernen",
"detAttSave": "Speichern unter …",
"detEmpty": "Ihre Passwörter werden hier angezeigt",
"detGroupRestore": "Ziehen Sie diese Gruppe in eine andere Gruppe als den Papierkorb, um sie wiederherzustellen.",
"detHistoryClickPoint": "Klicken Sie auf einen der Punkte im Verlauf um den entsprechenden Zustand des Eintrags anzuzeigen",
"detHistoryClickPoint": "Klicken Sie auf einen der Punkte im Verlauf, um den entsprechenden Zustand des Eintrags anzuzeigen",
"detHistoryReturn": "zurück zum Eintrag",
"detHistoryRevert": "Auf diese Version zurücksetzen",
"detHistoryDel": "Version löschen",
@@ -236,11 +241,11 @@
"detHistoryRevertAlertBody": "Ihr aktueller Stand wird in der Historie gesichert.",
"detHistoryDeleteAlert": "Diesen Stand löschen?",
"detHistoryDeleteAlertBody": "Sie können ihn nicht wiederherstellen.",
"detHistoryDiscardChangesAlert": "Änderung verwerfen?",
"detHistoryDiscardChangesAlertBody": "Ungesicherte Änderungen sind unwiderruflich verloren.",
"detHistoryDiscardChangesAlert": "Änderungen an diesem Eintrag verwerfen?",
"detHistoryDiscardChangesAlertBody": "Ungespeicherte Änderungen gehen dabei unwiderruflich verloren.",
"detBackToList": "zurück zur Liste",
"detSetIconColor": "Farbe ändern",
"detSetIcon": "Icon ändern",
"detSetIcon": "Symbol ändern",
"detDropAttachments": "Anhänge hier ablegen",
"detDelEntry": "Löschen",
"detDelEntryPerm": "Dauerhaft löschen",
@@ -253,7 +258,9 @@
"detAttachments": "Anhänge",
"detDelFromTrash": "Aus dem Papierkorb löschen?",
"detDelFromTrashBody": "Es wird keine Möglichkeit zur Wiederherstellung geben.",
"detDelFromTrashBodyHint": "Um alle Dateien aus dem Papierkorb zu entfernen, klicken Sie auf das “Papierkorb” leeren-Icon im Papierkorb-Menüpunkt.",
"detDelFromTrashBodyHint": "Um alle Dateien aus dem Papierkorb zu entfernen, klicken Sie auf das „Papierkorb leeren“-Symbol im Papierkorb-Menüpunkt.",
"detDelToTrash": "Diesen Eintrag löschen?",
"detDelToTrashBody": "Der Eintrag wird in den Papierkorb verschoben.",
"detFieldCopied": "Kopiert",
"detFieldCopiedTime": "Kopiert für {} Sekunden",
"detCopyHint": "Sie können den Inhalt eines Feldes kopieren, indem Sie auf seine Beschriftung klicken",
@@ -265,18 +272,20 @@
"detMenuAddField": "{} hinzufügen",
"detMenuCopyPassword": "Passwort kopieren",
"detMenuCopyUser": "Benutzer kopieren",
"detSetupOtp": "Einweg-Passwörter",
"detMenuCopyOtp": "Einmal-Code kopieren",
"detSetupOtp": "Einmal-Codes",
"detClone": "Kopie erstellen",
"detCopyEntryToClipboard": "Alle Felder kopieren",
"detClonedName": "Kopie",
"detAutoType": "Auto-Type",
"detAutoTypeSettings": "Auto-Type Einstellungen",
"detAutoTypeEnabled": "Auto-Type für diesen Eintrag aktivieren",
"detAutoTypeSequence": "Tastensequenz",
"detAutoTypeSequence": "Tastenfolge",
"detAutoTypeInput": "Eingabe",
"detAutoTypeShortcutsDesc": "{} oder {} während die App inaktiv ist",
"detAutoTypeObfuscation": "Echte Tastenanschläge mit zufälligen mischen",
"detAutoTypeWindow": "Fenster",
"detAutoTypeInputWindow": "Fenster-Titel",
"detAutoTypeInputWindow": "Fenstertitel",
"detSetupOtpAlert": "QR-Code einscannen",
"detSetupOtpAlertBody": "Bitte kopieren Sie den QR-Code, der auf der Autorisierungsseite angezeigt wird.",
"detSetupOtpAlertBody1": "1. Gehen Sie zur Autorisierungsseite",
@@ -289,18 +298,35 @@
"detSetupOtpAlertBodyWith": "mit {}",
"detOtpImageError": "Fehler beim Einlesen des Bildes",
"detOtpImageErrorBody": "Entschuldigung, wir konnten das Bildformat nicht lesen. Bitte kontaktieren Sie den Hersteller mit Einzelheiten zu diesem Fehler.",
"detOtpImageReading": "QR-Code wird eingelesen...",
"detOtpImageReading": "QR-Code wird eingelesen …",
"detOtpQrError": "QR-Code Lesefehler",
"detOtpQrErrorBody": "Der QR-Code konnte leider nicht eingelesen werden. Bitte versuchen Sie es noch einmal oder kontaktieren Sie den Hersteller mit Einzelheiten zum aufgetretenen Fehler.",
"detOtpQrWrong": "Fehlerhafter QR-Code",
"detOtpQrWrongBody": "Ihr QR-Code wurde erfolgreich eingelesen, enthält jedoch kein Einweg-Passwort.",
"detOtpQrWrongBody": "Ihr QR-Code wurde erfolgreich eingelesen, enthält jedoch keinen Einmal-Code.",
"detOtpField": "Einmal-Code",
"detOtpClickToTouch": "Zum Erzeugen hier klicken",
"detOtpGenerating": "Wird erzeugt …",
"detOtpTouch": "Berühren Sie Ihren {}",
"detLockField": "Dieses Feld sperren, damit der Inhalt nicht durchsuchbar ist und angezeigt wird. Um ihn anzuzeigen, muss er angeklickt werden.",
"detUnlockField": "Dieses Feld entsperren. Dies führt dazu, dass der Inhalt direkt angezeigt wird und durchsuchbar ist.",
"detRevealField": "Anzeigen",
"detHideField": "Verbergen",
"detAutoTypeField": "Auto-Type",
"detIssuesHideTooltip": "Diese Warnung verstecken",
"detIssueWeakPassword": "Das Passwort ist schwach, es wird empfohlen es zu ändern.",
"detIssuePoorPassword": "Das Passwort ist schwach, es wird dringend empfohlen es zu ändern.",
"detIssuePwnedPassword": "Dieses Passwort wurde laut {} in einem Datenleck gefunden, es wird empfohlen das Passwort zu ändern.",
"detIssuePasswordCheckError": "Es gab einen Fehler bei der online-überprüfung des Passwort.",
"detIssueOldPassword": "Das Passwort ist alt.",
"detIssueCloseAlertHeader": "Verstecke Passwortmeldungen",
"detIssueCloseAlertBody": "Es gibt verschiedene Möglichkeiten diese Warnung zu verstecken:",
"detIssueCloseAlertEntry": "Nicht für diesen Eintrag anzeigen.",
"detIssueCloseAlertSettings": "Globale Einstellungen anpassen",
"autoTypeEntryFields": "Feld-Platzhalter",
"autoTypeModifiers": "Hilfstasten",
"autoTypeKeys": "Tasten",
"autoTypeLink": "mehr...",
"autoTypeError": "Auto-Type Fehler",
"autoTypeLink": "mehr …",
"autoTypeError": "Auto-Type-Fehler",
"autoTypeErrorGeneric": "Während der Ausführung von Auto-Type ist ein Fehler aufgetreten: {}",
"autoTypeErrorGlobal": "Um globale Tastenkürzel zu nutzen, wechseln Sie bitte zu der Anwendung, in der Sie das Passwort eingeben wollen.",
"autoTypeErrorNotInstalled": "{} ist nicht installiert",
@@ -308,9 +334,11 @@
"autoTypeMsgNoWindow": "Wir konnten den Titel des aktiven Fensters leider nicht auslesen. Fangen Sie einfach an zu tippen, um nach dem richtigen Eintrag zu suchen.",
"autoTypeMsgMatchedByWindow": "Passwort auswählen für {}",
"autoTypeNoMatches": "keine passenden Einträge",
"autoTypeSelectionHint": "Die Auto-Type Abfolge eintippen",
"autoTypeSelectionHint": "Die Auto-Type-Sequenz eintippen",
"autoTypeSelectionHintAction": "Nur das Passwort eintippen",
"autoTypeSelectionHintOpt": "Nur den Benutzernamen eintippen",
"autoTypeSelectionHintShift": "Andere Felder",
"autoTypeSelectionOtp": "Einmal-Code",
"appSecWarn": "Unsichere Verbindung!",
"appSecWarnBody1": "Sie haben diese App über eine ungesicherte Verbindung geöffnet, Sie könnten beobachtet und Ihre Passwörter könnten gestohlen werden. Wir empfehlen Ihnen dringend, die App hier nicht weiter zu nutzen, wenn Sie nicht genau wissen, was Sie tun.",
"appSecWarnBody2": "Ihre Datenbank ist zwar verschlüsselt, aber es kann nicht sichergestellt werden, dass die App nicht auf dem Web vom Server zu Ihrem Browser manipuliert wurde.",
@@ -324,25 +352,28 @@
"appSaveError": "Fehler beim Speichern",
"appSaveErrorBody": "Automatisches Speichern fehlgeschlagen",
"appSaveErrorBodyMul": "Automatisches Speichern fehlgeschlagen:",
"appSaveErrorExitLoseChanges": "Schließen und alle Änderungen verlieren",
"appSaveErrorExitLoseChangesBody": "Du kannst entweder die App schließen und alle Änderungen verlieren, oder gehe in die Dateieinstellungen und exportiere die Daten",
"appSettingsError": "Fehler beim Laden der App",
"appSettingsErrorBody": "Es gab einen Fehler beim Laden der App-Einstellungen. Bitte überprüfen Sie die App URL oder kontaktieren Sie Ihren Systemadministrator.",
"appNotSupportedError": "Ihr Browser wird nicht unterstützt.",
"appSettingsErrorBody": "Es gab einen Fehler beim Laden der App-Einstellungen. Bitte überprüfen Sie die App-URL oder kontaktieren Sie Ihren Systemadministrator.",
"appNotSupportedError": "Ihr Browser unterstützt einige wichtige Funktionen nicht, die für diese App benötigt werden.",
"appTabWarn": "Zu viele Tabs",
"appTabWarnBody": "KeeWeb kann nicht in mehreren Browser-Tabs gleichzeitig genutzt werden, bitte schließen Sie diesen Tab.",
"appRightsAlert": "Schreibschutz für KeeWeb wird eingerichtet",
"appRightsAlertBody1": "Ihre KeeWeb-Anwendung ist nicht gegen Änderungen von außen gesichert. Um diesen Schreibschutz einzurichten, benötigt die App Administratorrechte.",
"appRightsAlertBody2": "Sie möchten der App keine Administratorrechte erteilen? Mit folgendem Befehl können Sie den Schreibschutz auch von Hand im Terminal aktivieren",
"appBrowserAuthComplete": "Die Authentifizierung ist abgeschlossen, Sie können diesen Tab jetzt schließen.",
"setGenTitle": "Allgemeine Einstellungen",
"setGenUpdate": "Update",
"setGenNewVersion": "Eine neue Version der App ist verfügbar und wurde heruntergeladen",
"setGenReleaseNotes": "Versionshinweise anzeigen",
"setGenReloadToUpdate": "Seite aktualisieren, um das Update durchzuführen",
"setGenUpdateManual": "Eine neue Version ist verfügbar. Sie wird nach Updates suchen und sie automatisch installieren, ein automatisches Update von Ihrer Version ist aber nicht möglich.",
"setGenUpdateManual": "Eine neue Version ist verfügbar. Sie wird nach Updates suchen und diese automatisch installieren, ein automatisches Update Ihrer Version ist aber nicht möglich.",
"setGenDownloadUpdate": "Update herunterladen",
"setGenUpdateAuto": "Automatisch herunterladen und installieren",
"setGenUpdateCheck": "Auf Updates überprüfen aber nicht installieren",
"setGenUpdateCheck": "Auf Updates überprüfen, aber nicht installieren",
"setGenNoUpdate": "Nie nach Updates suchen",
"setGenUpdateChecking": "Suche nach Updates",
"setGenUpdateChecking": "Updates werden gesucht",
"setGenCheckUpdate": "Nach Updates suchen",
"setGenErrorChecking": "Updatesuche fehlgeschlagen",
"setGenLastCheckSuccess": "Letzte erfolgreiche Überprüfung am {}",
@@ -350,34 +381,50 @@
"setGenCheckedAt": "Überprüft am",
"setGenLatestVer": "Sie haben die aktuellste Version",
"setGenNewVer": "Neue Version {} verfügbar, veröffentlicht am",
"setGenDownloadingUpdate": "Update wird heruntergeladen...",
"setGenExtractingUpdate": "Update wird entpackt...",
"setGenDownloadingUpdate": "Update wird heruntergeladen …",
"setGenExtractingUpdate": "Update wird entpackt …",
"setGenCheckErr": "Beim Herunterladen der neuen Version ist ein Fehler aufgetreten",
"setGenNeverChecked": "Nie nach Updates gesucht",
"setGenRestartToUpdate": "App neu starten, um das Update durchzuführen",
"setGenDownloadAndRestart": "Update herunterladen und App neu starten",
"setGenAppearance": "Oberfläche",
"setGenTheme": "Theme",
"setGenThemeFb": "Flat blue",
"setGenThemeDb": "Dark brown",
"setGenThemeWh": "White",
"setGenThemeDefault": "Standard",
"setGenThemeDark": "Dunkel",
"setGenThemeLight": "Hell",
"setGenThemeBlue": "Flach blau",
"setGenThemeFb": "Mattblau",
"setGenThemeBl": "Hell blau",
"setGenThemeBrown": "Brownie",
"setGenThemeDb": "Dunkelbraun",
"setGenThemeLb": "Hell braun",
"setGenThemeTerminal": "Terminal",
"setGenThemeTe": "Terminal",
"setGenThemeHc": "High contrast",
"setGenThemeSd": "Solarized dark",
"setGenThemeSl": "Solarized light",
"setGenThemeLt": "Hell Terminal",
"setGenThemeHighContrast": "Hoher Kontrast",
"setGenThemeHc": "Hoher Kontrast",
"setGenThemeDc": "Dunkel Kontrast",
"setGenThemeSol": "Solarized",
"setGenThemeSd": "Solarisiert dunkel",
"setGenThemeSl": "Solarisiert hell",
"setGenMoreThemes": "Mehr Themes",
"setGenAutoSwitchTheme": "Automatisch zwischen hellem und dunklem Thema umschalten, sofern möglich",
"setGenLocale": "Sprache",
"setGenLocOther": "Andere Sprachen sind als Plugins verfügbar.",
"setGenFontSize": "Schriftgröße",
"setGenFontSizeNormal": "Standard",
"setGenFontSizeLarge": "Groß",
"setGenFontSizeLargest": "Größte",
"setGenTitlebarStyle": "Fenster-Stil (erfordert Neustart des Programms)",
"setGenTitlebarStyle": "Fensterstil (erfordert Neustart des Programms)",
"setGenTitlebarStyleDefault": "Standard",
"setGenTitlebarStyleHidden": "Eigener Titel",
"setGenTitlebarStyleHiddenInset": "Eigener Titel, verschiebbares Fenster",
"setGenShowSubgroups": "Einträge aus allen Untergruppen anzeigen",
"setGenTableView": "Einträge in Tabellenansicht anzeigen",
"setGenColorfulIcons": "Eigene Icons in der Listenansicht farbig anzeigen",
"setGenColorfulIcons": "Eigene Symbole in der Listenansicht farbig anzeigen",
"setGenUseMarkdown": "Markdown in Notizen",
"setGenUseGroupIconForEntries": "Für neue Einträge automatisch das Gruppensymbol verwenden",
"setGenDirectAutotype": "Wenn nur ein passender Eintrag gefunden wird, diesen automatisch für Auto-Type auswählen",
"setGenFunction": "Arbeitsweise",
"setGenAutoSyncOnClose": "Beim Schließen speichern und synchronisieren",
"setGenAutoSyncTimer": "Regelmäßig speichern und synchronisieren",
@@ -387,7 +434,7 @@
"setGenNoRememberKeyFiles": "Nicht merken",
"setGenRememberKeyFilesData": "Im internen App-Speicher ablegen",
"setGenRememberKeyFilesPath": "Nur Speicherort der Schlüsseldateien merken",
"setGenLockInactive": "Automatisch sperren, wenn die App inaktiv ist",
"setGenLockInactive": "Wenn die App inaktiv ist",
"setGenNoAutoLock": "Nicht automatisch sperren",
"setGenLockMinutes": "Nach {} Minuten",
"setGenLockHour": "In einer Stunde",
@@ -399,42 +446,66 @@
"setGenClearMinute": "Nach einer Minute",
"setGenMinInstead": "App beim Schließen stattdessen minimieren",
"setGenLock": "Automatisch sperren",
"setGenLockMinimize": "Beim Minimieren automatisch sperren",
"setGenLockMinimize": "Beim Minimieren der App",
"setGenLockCopy": "Nach dem Kopieren eines Passworts",
"setGenLockAutoType": "Bei Auto-Type",
"setGenLockOrSleep": "Bei Aktivierung von Bildschirmsperre oder Ruhezustand",
"setGenStorage": "Synchronisierung",
"setGenDisableOfflineStorage": "Geladene Dateien nicht in Offline-Speicher zwischenspeichern",
"setGenStorageLogout": "Abmelden",
"setGenShowAdvanced": "Erweiterte Einstellungen anzeigen",
"setGenDevTools": "Entwicklerwerkzeuge anzeigen",
"setGenTryBeta": "Beta-Version bis zum Schließen der App ausprobieren",
"setGenTryBeta": "Betaversion bis zum Schließen der App ausprobieren",
"setGenTryBetaWarning": "Ungespeicherte Dateien",
"setGenTryBetaWarningBody": "Bitte speichern Sie alle Dateien und Klicken Sie erneut auf diesen Button",
"setGenTryBetaWarningBody": "Bitte speichern Sie alle Dateien und klicken erneut auf diese Schaltfläche",
"setGenShowAppLogs": "App-Logs anzeigen",
"setGenReloadApp": "App neu laden",
"setGenFieldLabelDblClickAutoType": "Auto-Type durch Anklicken von Beschriftungen aktivieren",
"setGenTouchId": "Fingerabdruck",
"setGenTouchIdDisabled": "Fingerabdruck nicht benutzen",
"setGenTouchIdMemory": "Nur mit Fingerabdruck entsperren, wenn KeeWeb aktiv ist",
"setGenTouchIdFile": "Benutze immer den Fingerabdruck anstatt das Master-Passwort",
"setGenTouchIdPass": "Benötige Master-Passwort nach",
"setGenAudit": "Audit",
"setGenAuditPasswords": "Warnungen für schwache Passwörter anzeigen",
"setGenAuditPasswordEntropy": "Passwortlänge und Zufälligkeit prüfen",
"setGenExcludePinsFromAudit": "Kurze Pin-Codes niemals prüfen (z. B. 12345)",
"setGenHelpHIBP": "KeeWeb kann überprüfen ob deine Passwörter bei einem früheren Datenleck veröffentlicht wurden. Deine Passwörter können nicht beim übertragen ausgelesen werden, aber die Anzahl der überprüften Passwörter kann möglicherweise entdeckt werden. {} kannst du mehr über den Datenschutz beim Nutzen dieses Dienstes erfahren. Wenn diese Option aktiviert ist überprüft KeeWeb deine Passwörter automatisch.",
"setGenHelpHIBPLink": "hier",
"setGenAuditPasswordAge": "Alte Passwörter",
"setGenAuditPasswordAgeOff": "Zeige keine Warnungen über alte Passwörter",
"setGenAuditPasswordAgeOneYear": "Zeige Warnungen für Passwörter die über ein Jahr alt sind",
"setGenAuditPasswordAgeYears": "Zeige Warnungen für Passwörter die über {} Jahre alt sind",
"setFilePath": "Dateipfad",
"setFileStorage": "Diese Datei wird von {} geladen.",
"setFileIntl": "Diese Datei ist im internen App-Speicher abgelegt",
"setFileLocalHint": "Sie wollen nahtlos mit lokalen Dateien arbeiten?",
"setFileDownloadApp": "Laden Sie die Desktop-App herunter",
"setFileSave": "Speichern",
"setFileSaveTo": "Speichern unter...",
"setFileSaveTo": "Speichern unter …",
"setFileClose": "Sperren",
"setFileSync": "Synchronisierung",
"setFileSyncVerb": "Synchronisieren",
"setFileSaveToXml": "XML",
"setFileSaveToHtml": "HTML",
"setFileLastSync": "Letzte Synchronisierung",
"setFileLastSyncUnknown": "unbekannt",
"setFileSyncInProgress": "Synchronisierung läuft",
"setFileSyncError": "Synchronisierungsfehler",
"setFilePass": "Master-Passwort",
"setFileConfirmPass": "Master-Passwort bestätigen",
"setFilePass": "Hauptpasswort",
"setFileConfirmPass": "Masterpasswort bestätigen",
"setFilePassChange": "Um das Passwort zu ändern, geben Sie es im Bestätigungsfeld an",
"setFilePassChanged": "Das Passwort wurde geändert. Lassen Sie das Feld leer, um das bisherige Passwort zu behalten.",
"setFilePassNotMatch": "Die Passwörter stimmen nicht überein, bitte geben Sie sie erneut ein",
"setFilePassNotMatch": "Die Passwörter stimmen nicht überein, bitte geben Sie diese erneut ein",
"setFileKeyFile": "Schlüsseldatei",
"setFileSelKeyFile": "Schlüsseldatei auswählen",
"setFileNames": "Namen",
"setFileDefUser": "Standard-Benutzername",
"setFileEnableTrash": "Papierkorb aktivieren",
"setFileHistMode": "Eintragsverlauf",
"setFileHistLimited": "Alte Einträge im Verlauf automatisch löschen",
"setFileHistDisabled": "Keinen Verlauf speichern",
"setFileHistUnlimited": "Verlauf dauerhaft speichern",
"setFileHistLen": "Anzahl der im Verlauf gespeicherten Versionen",
"setFileHistSize": "Maximalgröße des Verlaufs pro Datei in MB",
"setFileBackups": "Sicherungen",
@@ -442,7 +513,7 @@
"setFileBackupPath": "Sicherungspfad",
"setFileBackupTime": "Sicherungen anlegen",
"setFileBackupNow": "Jetzt sichern",
"setFileBackupNowWorking": "Sichern...",
"setFileBackupNowWorking": "Ausführung läuft …",
"setFileBackupError": "Sicherungsfehler",
"setFileBackupErrorDescription": "Fehler beim Schreiben der Sicherungsdatei",
"setFileBackupErrorIsDir": "Der Sicherungspfad ist ungültig",
@@ -462,9 +533,9 @@
"setFileUseGenKeyFile": "Generierte Schlüsseldatei benutzen",
"setFileUseOldKeyFile": "Alte Schlüsseldatei benutzen",
"setFileGenKeyFile": "Neue Schlüsseldatei generieren",
"setFileDontUseKeyFile": "Keine Schlüsseldatei benutzen",
"setFileDontUseKeyFile": "Keine Schlüsseldatei verwenden",
"setFileEmptyPass": "Leeres Passwort",
"setFileEmptyPassBody": "Eine Datenbank ohne Passwort zu speichern macht sie vollkommen ungeschützt. Möchten Sie sie trotzdem speichern?",
"setFileEmptyPassBody": "Eine Datenbank ohne Passwort zu speichern, macht diese vollkommen ungeschützt. Möchten Sie dies trotzdem tun?",
"setFileSaveError": "Fehler beim Speichern",
"setFileSaveErrorBody": "Schreibfehler beim Speichern",
"setFileAlreadyExists": "Existiert bereits",
@@ -473,11 +544,22 @@
"setFileUnsavedBody": "Es gibt ungespeicherte Änderungen in dieser Datei",
"setFileCloseNoSave": "Sperren und Änderungen verwerfen",
"setFileDontClose": "Nicht sperren",
"setFileFormatVersion": "Dateiformat",
"setFileExportRaw": "Passwörter exportieren",
"setFileExportRawBody": "Die Exportdatei wird Ihre Passwörter als unverschlüsselten Klartext enthalten. Möchten Sie fortfahren?",
"setFileDeviceIntro": "Einmal-Codes aus diesem {} werden in der App angezeigt.",
"setFileDeviceSettings": "Einstellungen",
"setFileYubiKey": "YubiKey",
"setFileDontUseYubiKey": "Keinen YubiKey verwenden",
"setFileRefreshYubiKeyList": "Liste aktualisieren",
"setFileYubiKeyHeader": "YubiKey",
"setFileYubiKeyBody": "Es ist gefährlich, einen YubiKey als Teil des Hauptschlüssels zu verwenden. Falls etwas schief geht, besteht möglicherweise kein Zugriff mehr auf die Passwörter. Haben Sie ein Backup Ihrer Datei erstellt, bevor diese Einstellung geändert wurde?",
"setFileYubiKeyErrorEmptyMac": "Scheinbar wurde ein YubiKey angeschlossen, er ist aber nicht sichtbar. KeeWeb muss in den Sicherheitseinstellungen im Abschnitt Input-Monitoring hinzugefügt werden, um auf YubiKeys zugreifen zu können.",
"setShTitle": "Tastenkürzel",
"setShShowAll": "alle Einträge anzeigen",
"setShColors": "mit Farben markierte Einträge anzeigen",
"setShTrash": "Papierkorb öffnen",
"setShFind": "Suchfeld aktivieren; oder: einfach anfangen, den Suchbegriff zu tippen",
"setShFind": "Suchen oder einfach beginnen zu tippen",
"setShClearSearch": "Suchfeld leeren",
"setShCopyPass": "Passwort bzw. ausgewähltes Feld kopieren",
"setShCopyUser": "Benutzername kopieren",
@@ -486,20 +568,23 @@
"setShPrev": "zum vorherigen Eintrag gehen",
"setShNext": "zum nächsten Eintrag gehen",
"setShCreateEntry": "Neuer Eintrag",
"setShOpen": "öffnen / neu",
"setShSave": "alle Dateien speichern",
"setShOpen": "Öffnen / Neu",
"setShSave": "Alle Dateien speichern",
"setShGen": "Passwort generieren",
"setShSet": "App-Einstellungen",
"setShCopyPassGlobal": "Passwort kopieren (wenn die App im Hintergrund ist)",
"setShCopyUserGlobal": "Usernamen kopieren (wenn die App im Hintergrund ist)",
"setShCopyUrlGlobal": "Website kopieren (wenn die App im Hintergrund ist)",
"setShAutoTypeGlobal": "Auto-Type (wenn die App im Hintergrund ist)",
"setShCopyPassGlobal": "Passwort kopieren",
"setShCopyOtp": "Einmal-Passwort kopieren",
"setShAutoTypeGlobal": "Auto-Type",
"setShCopyPassOnly": "Passwort kopieren",
"setShRestoreApp": "{} öffnen",
"setShGlobal": "Diese systemweiten Tastenkürzel funktionieren auch, wenn die App im Hintergrund läuft. Klicken Sie auf einen Eintrag, um ein eigenes Kürzel festzulegen.",
"setShLock": "Datenbank sperren",
"setShEdit": "Drücken Sie eine Tastenkombination, um diese als Kürzel zu festzulegen",
"setPlInstallTitle": "Neue Plugins installieren",
"setPlInstallDesc": "KeeWeb-Plugins fügen Funktionen, Themes und Sprachen zu KeeWeb hinzu. Plugins werden mit denselben Rechten ausgeführt wie KeeWeb selbst, sie können auf all Ihre Passwörter zugreifen oder diese ändern. Installieren Sie niemals Plugins, denen Sie nicht vertrauen.",
"setPlInstallLabel": "Plugin-URL",
"setPlInstallBtn": "Installieren",
"setPlInstallBtnProgress": "Installiere",
"setPlInstallBtnProgress": "Installation läuft",
"setPlUninstallBtn": "Deinstallieren",
"setPlDisableBtn": "Deaktivieren",
"setPlEnableBtn": "Aktivieren",
@@ -513,7 +598,7 @@
"setPlLoadTime": "geladen in {}",
"setPlLastUpdate": "Letzte Prüfung auf Updates",
"setPlLoadError": "Fehler beim Laden des Plugins",
"setPlGalleryLoading": "Plugins werden geladen, bitte warten Sie einen Moment",
"setPlGalleryLoading": "Plugins werden geladen, bitte einen Moment warten",
"setPlGalleryLoadError": "Fehler beim Laden der Plugins",
"setPlInstallUrlTitle": "Plugin von einer URL hinzufügen",
"setPlInstallUrlDesc": "Wenn das Plugin nicht in der Galerie verfügbar ist, können Sie es manuell von einer URL installieren",
@@ -525,20 +610,40 @@
"setPlTranslateLink": "übersetzen Sie die App in Ihre Sprache",
"setPlAutoUpdate": "Automatisch aktualisieren",
"setPlLoadGallery": "Plugin-Galerie laden",
"setDevicesTitle": "Geräte",
"setDevicesEnableUsb": "Interaktion mit USB-Geräten aktivieren",
"setDevicesYubiKeyIntro": "Es wird empfehlen {} zu lesen, bevor ein YubiKey verwendet wird.",
"setDevicesYubiKeyIntroLink": "dieses Dokument",
"setDevicesYubiKeyToolsDesc": "Um YubiKey in diesem Modus verwenden zu können, müssen Sie vorher das Tool {} installieren.",
"setDevicesYubiKeyToolsDesc2": "{}, um mehr Informationen über dieses Tool zu erhalten.",
"setDevicesYubiKeyToolsDescLink": "Hier klicken",
"setDevicesYubiKeyToolsStatusChecking": "Prüfung, ob {} installiert ist",
"setDevicesYubiKeyToolsStatusOk": "{} ist installiert",
"setDevicesYubiKeyToolsStatusError": "{} ist nicht installiert oder funktioniert nicht korrekt",
"setDevicesYubiKeyOtpTitle": "Einmal-Codes",
"setDevicesYubiKeyOtpDesc": "Ein YubiKey kann genutzt werden, um Einmal-Codes für verschiedene Dienste zu erzeugen.",
"setDevicesYubiKeyOtpShowIcon": "Das Symbol auf der Startseite anzeigen",
"setDevicesYubiKeyOtpAutoOpen": "Einmal-Codes automatisch laden, wenn Dateien geöffnet sind",
"setDevicesYubiKeyOtpMatchEntries": "Passende Einmal-Codes in den Einträgen anzeigen",
"setDevicesYubiKeyChalRespTitle": "Challenge-Response",
"setDevicesYubiKeyChalRespDesc": "Es ist auch möglich, einen YubiKey im Challenge-Response-Modus zu verwenden, um einen Teil des Private Schlüssels, der zum Verschlüsseln der Dateien verwendet wird, auf dem YubiKey zu speichern.",
"setDevicesYubiKeyChalRespShow": "Optionen zum Verwenden eines YubiKeys beim Öffnen von Dateien anzeigen",
"setDevicesYubiKeyStuckWorkaround": "YubiKey entfernen und neu verbinden, falls der Ladeprozess hängt",
"setDevicesYubiKeyRememberChalResp": "Challenge-Response-Einstellungen merken, während die App geöffnet ist",
"setAboutTitle": "Über",
"setAboutBuilt": "Diese App wurde mit den folgenden Werkzeugen erstellt",
"setAboutBuilt": "Diese App wurde mit folgenden Werkzeugen erstellt",
"setAboutLic": "Lizenz",
"setAboutLicComment": "Die App selbst und alle enthaltenen Komponenten, die nicht Public Domain sind, stehen unter der MIT-Lizenz.",
"setAboutFirst": "Dies ist eine Open-Source App, erstellt von {}",
"setAboutSecond": "und lizenziert unter {}.",
"setAboutSource": "Quellcode und Tickets befinden sich auf {}.",
"setHelpFormat": "Dateiformat",
"setHelpFormatBody": "Dies ist eine Portierung der {} App, programmiert mit Webtechnologien. Sie ist kompatibel mit Dateien im KeePass-Format (kdbx). Sie können solche Dateien (Passwort-Datenbanken) entweder mit KeePass oder mit dieser App erstellen. Das Dateiformat ist zu 100% kompatibel und sollte in beiden Anwendungen nutzbar sein.",
"setHelpFormatBody": "Dies ist eine Portierung der App {}, programmiert mit Webtechnologien. Sie ist kompatibel mit Dateien im KeePass-Format (kdbx). Sie können solche Dateien (Passwort-Datenbanken) entweder mit KeePass oder mit dieser App erstellen. Das Dateiformat ist zu 100 % kompatibel und sollte in beiden Anwendungen nutzbar sein.",
"setHelpProblems": "Probleme?",
"setHelpProblems1": "Falls etwas schief geht, {}",
"setHelpProblems2": "oder {}",
"setHelpOpenIssue": "eröffnen Sie bitte ein Ticket auf GitHub (englisch)",
"setHelpContactLink": "kontaktieren Sie einen Entwickler direkt",
"setHelpContactLink": "kontaktieren Sie den Entwickler direkt",
"setHelpAppInfo": "App-Informationen",
"setHelpOtherPlatforms": "Andere Plattformen",
"setHelpDesktopApps": "Deskop-Apps",
@@ -546,12 +651,15 @@
"setHelpUpdates": "Neuigkeiten",
"setHelpTwitter": "Twitter",
"dropboxSetupDesc": "Etwas Konfiguration ist notwendig, um Dropbox in einer selbst gehosteten Web-App zu verwenden. Bitte erstellen Sie eine eigene Dropbox-App und tragen Sie ihren App-Schlüssel unten ein.",
"dropboxAppKey": "Dropbox App-Schlüssel",
"dropboxAppKey": "Dropbox-App-Schlüssel",
"dropboxAppKeyDesc": "Kopieren Sie den Schlüssel aus Ihrer Dropbox-App (Entwicklereinstellungen)",
"dropboxAppKeyHint": "Ihr App-Schlüssel",
"dropboxAppSecret": "Dropbox-App-Secret",
"dropboxAppSecretDesc": "Das App-Secret ist neben dem App-Schlüssel zu finden",
"dropboxFolder": "App-Ordner",
"dropboxFolderDesc": "Wenn Ihre App mit der gesamten Dropbox verlinkt ist (anstatt mit einem bestimmten Ordner), geben Sie hier den Pfad zum Ordner mit Ihren KDBX-Dateien an.",
"dropboxFolderSettingsDesc": "Wählen Sie einen Ordner in Ihrer Dropbox, in dem die Dateien gespeichert werden (standardmäßig das Stammverzeichnis)",
"dropboxFolderPlaceholder": "Standard-Ordner",
"dropboxFolderPlaceholder": "Standardordner",
"dropboxLink": "App verlinken mit",
"dropboxLinkApp": "App-Ordner (Apps/KeeWeb)",
"dropboxLinkFull": "Gesamte Dropbox oder beliebiger Ordner",
@@ -560,8 +668,28 @@
"webdavSaveMethod": "Speichermethode",
"webdavSaveMove": "Eine temporäre Datei hochladen und verschieben",
"webdavSavePut": "kdbx-Datei mittels PUT überschreiben",
"launcherSave": "Passwort-Datenbank speichern",
"launcherSave": "Passwortdatenbank speichern",
"launcherFileFilter": "KeePass-Dateien",
"authPopupRequired": "Pop-Ups blockiert",
"authPopupRequiredBody": "Bitte erlauben Sie Pop-Ups für diese App in Ihrem Browser."
"authPopupRequired": "Pop-ups blockiert",
"authPopupRequiredBody": "Bitte erlauben Sie Pop-ups in Ihrem Browser.",
"exportFileInfo": "Dateiinformationen",
"exportHtmlName": "Name",
"exportHtmlDate": "Exportdatum",
"exportGenerator": "Software",
"exportDescription": "Diese Datei wurde mit {} erstellt.",
"importCsvTitle": "Aus CSV importieren",
"importCsvRun": "Importieren",
"importIgnoreField": "Ignorieren",
"importTo": "Einträge werden importiert nach:",
"importNewFile": "Neue Datei",
"yubiKeyStuckError": "Der YubiKey scheint nicht mehr zu funktionieren. Auto-Repair kann in den App-Einstellungen aktiviert werden.",
"yubiKeyNoKeyHeader": "YubiKey benötigt",
"yubiKeyNoKeyBody": "Bitte den YubiKey mit der Seriennummer {} anschließen",
"yubiKeySlot": "Anschluss",
"yubiKeyTouchRequestedHeader": "Bitte den YubiKey berühren",
"yubiKeyTouchRequestedBody": "Bitte den YubiKey mit der Seriennummer {} berühren",
"yubiKeyDisabledErrorHeader": "USB ist deaktiviert",
"yubiKeyDisabledErrorBody": "YubiKey ist zum Öffnen dieser Datei erforderlich. Bitte USB-Geräte in den Einstellungen aktivieren.",
"yubiKeyErrorWithCode": "YubiKey-Fehler, Code {}.",
"bioOpenAuthPrompt": "„{}“ öffnen"
}
@@ -1,50 +1,4 @@
{
"months": [
"Janvier",
"Février",
"Mars",
"Avril",
"Mai",
"Juin",
"Juillet",
"Août",
"Septembre",
"Octobre",
"Novembre",
"Décembre"
],
"monthsShort": [
"Janv",
"Févr",
"Mars",
"Avr",
"Mai",
"Juin",
"Juil",
"Août",
"Sept",
"Oct",
"Nov",
"Déc"
],
"weekdays": [
"Dimanche",
"Lundi",
"Mardi",
"Mercredi",
"Jeudi",
"Vendredi",
"Samedi"
],
"weekdaysShort": [
"Dim",
"Lun",
"Mar",
"Mer",
"Jeu",
"Ven",
"Sam"
],
"retToApp": "retour vers l'appli",
"name": "nom",
"icon": "icône",
@@ -61,30 +15,63 @@
"history": "historique",
"template": "modèle",
"notImplemented": "Non Implémenté",
"saveChanges": "Sauver les modifs",
"discardChanges": "Annuler les modifs",
"saveChanges": "Sauvegarder les modifications",
"discardChanges": "Annuler les modifications",
"advanced": "Avancé",
"shortcuts": "Raccourcis",
"help": "Aide",
"settings": "Paramètres",
"plugins": "Modules",
"plugins": "Modules (plugins)",
"ctrlKey": "ctrl",
"shiftKey": "shift",
"altKey": "alt",
"error": "erreur",
"oneMinute": "une minute",
"minutes": "{} minutes",
"oneHour": "une heure",
"hours": "{} heures",
"oneDay": "un jour",
"days": "{} jours",
"oneWeek": "une semaine",
"oneMonth": "un mois",
"oneYear": "une année",
"cache": "cache",
"file": "fichier",
"device": "appareil",
"webdav": "WebDAV",
"dropbox": "Dropbox",
"gdrive": "Google Drive",
"onedrive": "OneDrive",
"menuAllItems": "Tous les items",
"menuAllItems": "Tout",
"menuColors": "Couleurs",
"menuTrash": "Corbeille",
"menuSetGeneral": "Général",
"menuSetAbout": "A propos",
"menuSetAbout": "À propos",
"menuSetDevices": "Appareils",
"menuAlertNoTags": "Aucun tag",
"menuAlertNoTagsBody": "Vous pouvez ajouter de nouveaux tags en éditant les champs, dans la section tags.",
"menuAlertNoTagsBody": "Vous pouvez ajouter de nouveaux tags en éditant les champs, dans la section Tags.",
"menuEmptyTrash": "Vider la Corbeille",
"menuEmptyTrashAlert": "Vider la Corbeille?",
"menuEmptyTrashAlert": "Vider la Corbeille ?",
"menuEmptyTrashAlertBody": "Vous ne pourrez plus récupérer ces éléments",
"menuItemCollapsed": "Double-cliquer pour déplier",
"menuItemCollapsed": "Double-cliquez pour déplier",
"menuRestoreApp": "Ouvrir {}",
"menuQuitApp": "Quitter {}",
"sysMenuAboutKeeWeb": "A propos {}",
"sysMenuServices": "Services",
"sysMenuHide": "Cacher {}",
"sysMenuHideOthers": "Cacher autres",
"sysMenuUnhide": "Montrer tous",
"sysMenuQuit": "Quitter {}",
"sysMenuEdit": "Editer",
"sysMenuUndo": "Annuler",
"sysMenuRedo": "Répéter",
"sysMenuCut": "Couper",
"sysMenuCopy": "Copier",
"sysMenuPaste": "Coller",
"sysMenuSelectAll": "Tout sélectionner",
"sysMenuWindow": "Fenêtre",
"sysMenuMinimize": "Réduire",
"sysMenuClose": "Fermer fenêtre",
"alertYes": "Oui",
"alertNo": "Non",
"alertOk": "OK",
@@ -95,24 +82,26 @@
"alertDoNotAsk": "Ne plus me le redemander",
"appBeta": "ATTENTION: version beta, aperçu seulement",
"footerOpen": "Ouvrir/Nouveau",
"footerSyncError": "Erreur de synchro",
"footerSyncError": "Erreur de synchronisation",
"footerTitleGen": "Générer",
"footerTitleLock": "Verrouiller",
"genLen": "Longueur",
"genNewPass": "Nouveau mot de passe",
"genPresetDefault": "réglages par défaut",
"genPresetDerived": "comme ancien mot de passe",
"genPresetDerived": "similaire à l'ancien mot de passe",
"genPresetPronounceable": "prononçable",
"genPresetMed": "longueur moyenne",
"genPresetLong": "long",
"genPresetPin4": "code à 4 chiffres",
"genPresetMac": "adresse MAC",
"genPresetHash128": "hash 128-bit",
"genPresetHash256": "hash 256-bit",
"genPresetHash128": "hash 128 bits",
"genPresetHash256": "hash 256 bits",
"genHidePass": "Masquer le mot de passe",
"genShowPass": "Afficher le mot de passe",
"grpTitle": "Groupe",
"grpSearch": "Activer la recherche dans les entrées de ce groupe",
"grpAutoType": "Activer l'auto-complétion",
"grpAutoTypeSeq": "Séquence auto-complétion",
"grpAutoTypeSeq": "Séquence d'auto-complétion",
"grpAutoTypeSeqDefault": "Utiliser la séquence d'auto-complétion par défaut",
"grpTrash": "Supprimer le groupe et toutes ses entrées",
"tagTitle": "Tag",
@@ -123,8 +112,8 @@
"tagExists": "Ce tag existe déjà",
"tagExistsBody": "Un tag existe déjà avec ce nom. Merci de choisir un autre nom.",
"tagBadName": "Nom invalide",
"tagBadNameBody": "Un nom de tag ne peut pas contenir les caractères {}. Merci de les supprimer.",
"genPsTitle": "Générateur de préréglage",
"tagBadNameBody": "Les noms de Tag ne peuvent contenir les caractères {}. Veuillez les supprimer.",
"genPsTitle": "Préréglages du Générateur",
"genPsCreate": "Nouveau préréglage",
"genPsDelete": "Supprimer préréglage",
"genPsNew": "préréglage",
@@ -136,25 +125,29 @@
"genPsDigits": "Chiffres",
"genPsSpecial": "Caractères spéciaux",
"genPsBrackets": "Parenthèses",
"genPsHigh": "Caractères ASCII hauts",
"genPsHigh": "Caractères ASCII étendus",
"genPsAmbiguous": "Caractères ambigus",
"genPsInclude": "Caractères additionnels à inclure",
"genPsExample": "Exemple de mot de passe généré",
"keyChangeTitleRemote": "Clé maître changée",
"keyChangeMessageRemote": "La clé maître a été changée pour cette base de donnée. Merci d'entrer une nouvelle clé",
"keyChangeTitleExpired": "Clé maître expirée",
"keyChangeMessageExpired": "La clé maître pour cette base de donnée est expirée. Merci d'entrer une nouvelle clé",
"genPsPattern": "Modèle",
"genPsPatternHelp": "Des modèles peuvent être utilisés pour spécifier des règles de sélection de caractères. 1-AA générera un mot de passe commençant par un chiffre, suivi d'un tiret et de 2 lettres. Vous pouvez utiliser ces symboles :",
"genPsAllRanges": "Tous les caractères",
"genPsIncluded": "Caractères additionnels ajoutés ci-dessus",
"keyChangeTitleRemote": "Clé Maître Modifiée",
"keyChangeMessageRemote": "La clé maître a été modifiée pour cette base de données. Merci de saisir une nouvelle clé.",
"keyChangeTitleExpired": "Clé Maître Expirée",
"keyChangeMessageExpired": "La clé maître pour cette base de donnée est expirée. Merci de saisir une nouvelle clé.",
"keyChangeRepeatPassword": "Mot de passe, encore une fois",
"keyEnter": "Entrée",
"iconFavTitle": "Télécharger et utiliser le favicon du site web",
"iconSelCustom": "Sélectionner un icône personnalisé",
"iconSelCustom": "Sélectionner une icône personnalisée",
"listEmptyTitle": "Vide",
"listEmptyAdd": "ajouter avec le bouton {} au-dessus",
"listGroup": "Groupe",
"listNoWebsite": "aucun site web",
"listNoUser": "aucun utilisateur",
"listNoAttachments": "aucune pièce-jointe",
"listAddTemplateHeader": "Templates",
"listAddTemplateHeader": "Modèles",
"listAddTemplateBody1": "Les modèles (templates) vous permettent de créer des nouvelles entrées en un clic. Ajouter quelque chose à l'entrée du modèle et ensuite cliquer de nouveau sur {} pour utiliser ce modèle.",
"listAddTemplateBody2": "Vous pouvez toujours retrouver vos modèles dans le groupe {}.",
"searchAddNew": "Ajouter Nouveau",
@@ -174,32 +167,36 @@
"searchOptions": "Options",
"searchCase": "Respecte la casse",
"searchRegex": "RegEx",
"searchRank": "Auto",
"searchExact": "Exact",
"openOpen": "Ouvrir",
"openNew": "Nouveau",
"openNewFile": "Nouveau",
"openMore": "Plus",
"openDemo": "Démo",
"openGenerate": "Générer",
"openXml": "Importer XML",
"openCaps": "Majuscules activés",
"openCaps": "Majuscules activées",
"openClickToOpen": "Cliquer pour ouvrir un fichier",
"openKeyFile": "fichier clé",
"openKeyFileDropbox": "(depuis DropBox)",
"openDropHere": "déposez les fichiers ici",
"openFailedRead": "Échec lors de la lecture du fichier",
"openNothingFound": "Aucun résultat",
"openNothingFoundBody": "Aucun fichier ne peut être ouvert.",
"openNothingFoundBody": "Nous n'avons trouvé aucun fichier convenable.",
"openSelectFile": "Sélectionnez un fichier",
"openSelectFileBody": "Sélectionnez le fichier que vous voudriez ouvrir",
"openSelectFileBody": "Sélectionnez un fichier que vous voudriez ouvrir",
"openPassFor": "Mot de passe pour",
"openRemoveLastQuestion": "Supprimer le fichier local ?",
"openRemoveLastQuestionBody": "Le fichier que vous voulez supprimer est sauvegardé dans l'appli. Le supprimer de façon définitive ?",
"openRemoveLastQuestionModBody": "Le fichier que vous voulez supprimer a des modifications locales. Le supprimer et annuler ces modifications ?",
"openLocalFile": "Fichier local",
"openLocalFileBody": "Vous allez ouvrir un fichier qui sera stocké à l'intérieur de l'app. Les modifications apportées ne seront pas sauvegardés vers le système de fichiers. Pour obtenir le fichier avec vos données, exporter à partir des paramètres.",
"openLocalFileBody": "Vous allez ouvrir un fichier qui sera stocké dans l'application. Les modifications apportées ne seront pas sauvegardées vers le système de fichiers. Pour obtenir le fichier avec vos données, exportez-le via les paramètres.",
"openLocalFileDontShow": "Ne plus afficher",
"openWrongFile": "Fichier invalide",
"openWrongFileBody": "Ce format de fichier n'est pas supporté. Cette application fonctionne avec des fichiers de base de donnée KeePass (kdbx).",
"openKdbFileBody": "Vous essayez d'ouvrir un ancien fichier de base de donnée KeePass (KDB). Cette application supporte uniquement le nouveaux format (kdbx), merci d'utiliser KeePass 2 afin de convertir celui-ci.",
"openConfigHeader": "{} Paramètres",
"openConfigHeader": "Paramètres {}",
"openUrl": "URL",
"openUrlDesc": "https://serveur/chemin/fichier.kdbx, ou seulement fichier.kdbx",
"openUser": "Nom d'utilisateur",
@@ -212,12 +209,20 @@
"openConfigErrorNotFound": "Aucun fichier trouvé",
"openError": "Erreur",
"openErrorDescription": "Une erreur est survenue à l'ouverture du fichier",
"openErrorDescriptionMaybeTouchIdChanged": "L'erreur ressemble à ce qu'y arrive habituellement quand la configuration de Touch ID a été changée. Par exemple, vous avez ajouté ou supprimé un doigt supplémentaire. Si c'est le cas, allez dans Paramètres, désactiver Touch ID et activer le de nouveau.",
"openErrorFileNotFound": "Fichier non trouvé",
"openListErrorBody": "Erreur au chargement de la liste des fichiers",
"openShowAllFiles": "Tous les fichiers",
"detAttDownload": "Cliquer sur le bouton de pièce-jointe en pressant la touche Maj ou",
"openFileNoCacheError": "Fichier non trouvé dans la mémoire cache. Cela peut arriver parce que le stockage du navigateur a été nettoyé. Pour ouvrir le fichier, supprimez-le de KeeWeb et ajoutez-le à nouveau.",
"openChalRespHeader": "Challenge-Réponse",
"openChalRespLoading": "Chargement de la liste des YubiKeys",
"openChalRespSelectYubiKey": "Sélectionnez une YubiKey que vous voudriez utiliser",
"openChalRespErrorEmpty": "Pas de clé YubiKey trouvée.",
"openChalRespErrorEmptyMac": "Première fois que vous utilisez cette fonctionnalité sur MacOS ? KeeWeb doit avoir été autorisé dans la section \"Surveillance de l’entrée\" des paramètres de sécurité.",
"detAttDownload": "Cliquez sur le bouton de pièce-jointe en pressant la touche Maj pour le télécharger ou",
"detAttDelToRemove": "Supprimer pour enlever",
"detEmpty": "Vos mot de passe seront affichés ici",
"detAttSave": "Enregistrer sous",
"detEmpty": "Vos mots de passe seront affichés ici",
"detGroupRestore": "Pour restaurer ce groupe, veuillez le glisser-déposer dans un des groupes hors de la corbeille",
"detHistoryClickPoint": "Cliquer sur une entrée de l'historique pour voir son état",
"detHistoryReturn": "Retour vers l'entrée",
@@ -236,8 +241,8 @@
"detHistoryRevertAlertBody": "L'état courant sera sauvegardé dans l'historique.",
"detHistoryDeleteAlert": "Supprimer cet état de l'historique ?",
"detHistoryDeleteAlertBody": "Vous ne pourrez plus le restaurer.",
"detHistoryDiscardChangesAlert": "Oublier les changements fait à cette entrée ?",
"detHistoryDiscardChangesAlertBody": "Les changements non sauvegardés seront définitivement perdus.",
"detHistoryDiscardChangesAlert": "Ne pas sauvegarder les modifications de cette entrée ?",
"detHistoryDiscardChangesAlertBody": "Les changements non sauvegardés seront définitivement perdus, il n'y a pas de retour en arrière.",
"detBackToList": "retour vers liste",
"detSetIconColor": "Changer de couleur",
"detSetIcon": "Changer d'icône",
@@ -254,9 +259,11 @@
"detDelFromTrash": "Supprimer de la Corbeille ?",
"detDelFromTrashBody": "Vous ne pourrez plus le récupérer.",
"detDelFromTrashBodyHint": "Pour supprimer tous les éléments de la Corbeille, cliquez l’icône \"Vider la corbeille\" du menu Corbeille.",
"detDelToTrash": "Supprimer l'entrée ?",
"detDelToTrashBody": "L'entrée sera déplacée dans la corbeille.",
"detFieldCopied": "Copié",
"detFieldCopiedTime": "Copié pendant {} secondes",
"detCopyHint": "Vous pouvez copier la valeur du champ en cliquant sur son titre",
"detCopyHint": "Vous pouvez copier la valeur du champ en cliquant sur ton titre",
"detMore": "plus",
"detClickToAddField": "cliquez pour ajouter un nouveau champ",
"detMenuAddNewField": "Ajouter nouveau champ",
@@ -265,8 +272,10 @@
"detMenuAddField": "Ajouter {}",
"detMenuCopyPassword": "Copier mot de passe",
"detMenuCopyUser": "Copier nom",
"detSetupOtp": "Mots de passe à usage unique",
"detMenuCopyOtp": "Copier le code à usage unique",
"detSetupOtp": "Codes à usage unique",
"detClone": "Dupliquer",
"detCopyEntryToClipboard": "Copier tous les champs",
"detClonedName": "Copier",
"detAutoType": "Saisie auto",
"detAutoTypeSettings": "Paramètres saisie auto",
@@ -277,32 +286,50 @@
"detAutoTypeObfuscation": "Mélanger touches réelles et aléatoire",
"detAutoTypeWindow": "Fenêtre",
"detAutoTypeInputWindow": "Titre de fenêtre",
"detSetupOtpAlert": "Scanner le code QR",
"detSetupOtpAlertBody": "Veuillez copier le code QR qui est affiché sur la page d'autorisation",
"detSetupOtpAlert": "Scanner le QR code",
"detSetupOtpAlertBody": "Veuillez copier le QR code qui est affiché sur la page d'autorisation",
"detSetupOtpAlertBody1": "1. aller sur la page d'autorisation",
"detSetupOtpAlertBody2": "2. faire une capture d'écran du code QR {}",
"detSetupOtpAlertBody3": "3. coller la ici {}",
"detSetupOtpAlertBody3Mobile": "3. Selectionner ou scanner avec votre appareil photo en utilisant Selectionner/Scan ci-dessous",
"detSetupOtpAlertBody2": "2. faire une capture d'écran du QR code avec {}",
"detSetupOtpAlertBody3": "3. collez-la ici avec {}",
"detSetupOtpAlertBody3Mobile": "3. Sélectionner ou scanner avec votre appareil photo en utilisant Sélectionner/Scan ci-dessous",
"detSetupOtpAlertBody4": "Si vous ne pouvez pas scanner le code, cliquer sur Entrer le code manuellement",
"detSetupOtpManualButton": "Entrer le code manuellement",
"detSetupOtpScanButton": "Selectionner/Scan",
"detSetupOtpScanButton": "Sélectionner/Scan",
"detSetupOtpAlertBodyWith": "avec {}",
"detOtpImageError": "Erreur de lecture de l'image",
"detOtpImageErrorBody": "Désolé, le format de l'image ne peut pas être lu, merci de contacter les auteurs de l'application avec le détail de l'erreur.",
"detOtpImageReading": "Lecture du code QR...",
"detOtpQrError": "Erreur lecture du code QR",
"detOtpQrErrorBody": "Désolé le QR code ne peut pas être lu, essayez à nouveau ou contacter les auteurs de l'application avec le détail de l'erreur.",
"detOtpQrWrong": "Code QR incorrect",
"detOtpQrWrongBody": "Votre QR code a été scanné avec succès mais il ne contient pas d'information pour un mot de passe à usage unique.",
"detOtpImageReading": "Lecture du QR code...",
"detOtpQrError": "Erreur lecture du QR code",
"detOtpQrErrorBody": "Désolé, le QR code n'a pas pu être lu, essayez à nouveau ou contacter les auteurs de l'application avec le détail de l'erreur.",
"detOtpQrWrong": "QR code incorrect",
"detOtpQrWrongBody": "Votre code QR code a été scanné avec succès mais il ne contient pas d'information pour un code à usage unique.",
"detOtpField": "Code à usage unique",
"detOtpClickToTouch": "Cliquer pour générer",
"detOtpGenerating": "Création...",
"detOtpTouch": "Touchez votre {}",
"detLockField": "Verrouiller ce champ, ainsi son contenu ne sera pas visible ni ne pourra être cherché. Visualiser son contenu exigera de le cliquer explicitement.",
"detUnlockField": "Déverrouiller ce champ, rendant son contenu immédiatement visible et pouvant être cherché",
"detRevealField": "Révéler",
"detHideField": "Cacher",
"detAutoTypeField": "Saisie auto",
"detIssuesHideTooltip": "Cacher cet avertissement",
"detIssueWeakPassword": "Ce mot de passe est faible, nous vous recommandons de le changer",
"detIssuePoorPassword": "Ce mot de passe est très faible, nous vous recommandons très fort de le changer",
"detIssuePwnedPassword": "Ce mot de passe a été exposé à une faille selon {}, il est recommandé de le changer",
"detIssuePasswordCheckError": "Une erreur est survenue en vérifiant la force du mot de passe en ligne",
"detIssueOldPassword": "Ce mot de passe est vieux",
"detIssueCloseAlertHeader": "Cacher les problèmes de mots de passe",
"detIssueCloseAlertBody": "Il y a plusieurs façon de cacher ce message :",
"detIssueCloseAlertEntry": "Ne plus montrer pour cette entrée",
"detIssueCloseAlertSettings": "Modifier les paramètres globaux",
"autoTypeEntryFields": "Champs",
"autoTypeModifiers": "Touches modificatrices",
"autoTypeKeys": "Clés",
"autoTypeLink": "plus...",
"autoTypeError": "Erreur saisie auto",
"autoTypeErrorGeneric": "Il y a eu une erreur lors de la saisie automatique : {}",
"autoTypeErrorGlobal": "Pour utiliser le raccourci, sélectionner dans l'application là où vous voulez saisir le mot de passe",
"autoTypeErrorAccessibilityMacOS": "Nous avons essayé d'envoyer les frappes de caractères à cette application mais cela ne semble pas fonctionner parce qu'il manque des permissions. Cliquer ici pour en lire plus.",
"autoTypeErrorGlobal": "Pour utiliser un raccourci global, sélectionner l'application là où vous voulez saisir le mot de passe",
"autoTypeErrorNotInstalled": "{} n'est pas installé",
"autoTypeHeader": "Saisie auto : Selectionner",
"autoTypeMsgNoWindow": "Nous n'avons pas pu obtenir le titre de la fenêtre active, commencez à taper pour rechercher",
@@ -311,6 +338,8 @@
"autoTypeSelectionHint": "Saisissez la séquence automatique",
"autoTypeSelectionHintAction": "Entrez seulement le mot de passe",
"autoTypeSelectionHintOpt": "Entrez seulement le compte",
"autoTypeSelectionHintShift": "Autres champs",
"autoTypeSelectionOtp": "code à usage unique",
"appSecWarn": "Non sécurisé !",
"appSecWarnBody1": "Vous avez chargé cette appli avec une connexion non sécurisée. Quelqu'un peut vous observer et voler vos mots de passe. Nous vous recommandons fortement d'arrêter cette connexion, à moins que vous ne compreniez exactement ce que vous faites.",
"appSecWarnBody2": "Oui, votre base est chiffrée mais personne ne peut garantir que l'application n'a pas été modifiée avant d'arriver à vous.",
@@ -322,22 +351,25 @@
"appCannotLock": "Vous avez des modifications non sauvegardées qui seront perdus. Continuer ?",
"appAutoSave": "Sauver les modifications automatiquement",
"appSaveError": "Sauver l'erreur",
"appSaveErrorBody": "Echec sauvegarde auto du fichier",
"appSaveErrorBodyMul": "Echec sauvegarde auto des fichiers",
"appSaveErrorBody": "Échec sauvegarde auto du fichier",
"appSaveErrorBodyMul": "Échec sauvegarde auto des fichiers",
"appSaveErrorExitLoseChanges": "Afsluiten en alle aanpassingen kwijtraken",
"appSaveErrorExitLoseChangesBody": "Je kunt de app afsluiten en alle wijzigingen kwijtraken, of je kunt de bestandsinstellingen gebruiken om gegevens te exporteren",
"appSettingsError": "Erreur lancement appli",
"appSettingsErrorBody": "Il y a eu une erreur au chargement des paramètres. Merci de revérifier l'URL de l'application ou contacter votre administrateur.",
"appNotSupportedError": "Votre navigateur n'est pas supporté.",
"appSettingsErrorBody": "Il y a eu une erreur lors du chargement des paramètres. Merci de revérifier l'URL de l'application ou contacter votre administrateur.",
"appNotSupportedError": "Votre navigateur n'est pas compatible avec certaines fonctionnalités importantes que nous utilisons.",
"appTabWarn": "Trop d'onglets",
"appTabWarnBody": "KeeWeb ne peut être utilisé dans 2 onglets de navigateurs simultanément. Fermer cet onglet, s'il vous plait.",
"appRightsAlert": "Protéger l'appli KeeWeb",
"appRightsAlertBody1": "Votre application KeeWeb est accessible en écriture. Nous demandons les droits administrateurs pour le mettre en écriture uniquement pour les administrateurs.",
"appRightsAlertBody2": "Vous ne voulez pas donner les permissions ? Vous pouvez le faire vous-même à partir d'un terminal",
"appBrowserAuthComplete": "Authentification terminée, vous pouvez fermer cet onglet.",
"setGenTitle": "Paramètres",
"setGenUpdate": "Mettre à jour",
"setGenNewVersion": "Une nouvelle version a été téléchargée",
"setGenReleaseNotes": "Voir les notes de version",
"setGenReloadToUpdate": "Recharger pour mettre à jour",
"setGenUpdateManual": "Une nouvelle version est disponible. Elle vérifiera les mises à jour et les installera automatiquement, mais une mise à jour automatique à partir de votre version n'est pas possible.",
"setGenUpdateManual": "Une nouvelle version est disponible. Elle vérifiera les mises à jour et les installera automatiquement, mais cette mise à jour automatique à partir de votre version n'est pas possible.",
"setGenDownloadUpdate": "Télécharger mise à jour",
"setGenUpdateAuto": "Télécharger et installer automatiquement",
"setGenUpdateCheck": "Vérifier mais ne pas installer",
@@ -354,17 +386,30 @@
"setGenExtractingUpdate": "Décompression de la mise à jour...",
"setGenCheckErr": "Une erreur est intervenue durant le téléchargement de la mise à jour",
"setGenNeverChecked": "Ne jamais vérifier les mises à jour",
"setGenRestartToUpdate": "Redémarrer pour mettre à jour",
"setGenRestartToUpdate": "Redémarrer KeeWeb pour mettre à jour",
"setGenDownloadAndRestart": "Télécharger la mise à jour et redémarrer",
"setGenAppearance": "Apparence",
"setGenTheme": "Thème",
"setGenThemeFb": "Bleu plat",
"setGenThemeDefault": "Défaut",
"setGenThemeDark": "Sombre",
"setGenThemeLight": "Clair",
"setGenThemeBlue": "Bleu",
"setGenThemeFb": "Bleu foncé",
"setGenThemeBl": "Bleu clair",
"setGenThemeBrown": "Brownie",
"setGenThemeDb": "Marron foncé",
"setGenThemeWh": "Blanc",
"setGenThemeLb": "Brun clair",
"setGenThemeTerminal": "Terminal",
"setGenThemeTe": "Terminal",
"setGenThemeLt": "Terminal clair",
"setGenThemeHighContrast": "Contraste élevé",
"setGenThemeHc": "Contraste élevé",
"setGenThemeDc": "Contraste foncé",
"setGenThemeSol": "Solarisé",
"setGenThemeSd": "Solarized dark",
"setGenThemeSl": "Solarized light",
"setGenMoreThemes": "Plus de thèmes",
"setGenAutoSwitchTheme": "Basculer automatiquement entre les thèmes clairs et foncés lorsque possible",
"setGenLocale": "Langue",
"setGenLocOther": "d'autres langues sont disponibles en tant que modules",
"setGenFontSize": "Taille de police",
@@ -373,11 +418,14 @@
"setGenFontSizeLargest": "Très large",
"setGenTitlebarStyle": "Style de fenêtres (redémarrage requis)",
"setGenTitlebarStyleDefault": "Par défaut",
"setGenTitlebarStyleHidden": "Titre modifié",
"setGenTitlebarStyleHiddenInset": "Titre modifié, fénêtre déplaçable",
"setGenTitlebarStyleHidden": "Titre personnalisé",
"setGenTitlebarStyleHiddenInset": "Titre personnalisé, fenêtre déplaçable",
"setGenShowSubgroups": "Afficher les entrées de tous les sous groupes",
"setGenTableView": "Voir les entrées en liste",
"setGenColorfulIcons": "Icônes en couleur dans la liste",
"setGenColorfulIcons": "Icônes colorées dans la liste",
"setGenUseMarkdown": "Markdown dans les notes",
"setGenUseGroupIconForEntries": "Utilise automatiquement l'icône de groupe pour les nouvelles entrées",
"setGenDirectAutotype": "Si une seule entrée correspondante est trouvée, sélectionner celle-ci automatiquement pour l'autotype.",
"setGenFunction": "Opérations",
"setGenAutoSyncOnClose": "Sauvegarde et synchro automatique à la fermeture",
"setGenAutoSyncTimer": "Sauvegarde et synchro automatique régulièrement",
@@ -387,7 +435,7 @@
"setGenNoRememberKeyFiles": "Ne pas se souvenir",
"setGenRememberKeyFilesData": "Sauvegarder dans le stockage interne de l'appli",
"setGenRememberKeyFilesPath": "Se souvenir seulement des chemins des fichiers",
"setGenLockInactive": "si l'app est inactive",
"setGenLockInactive": "si l'application est inactive",
"setGenNoAutoLock": "Ne pas verrouiller automatiquement",
"setGenLockMinutes": "Dans {} minutes",
"setGenLockHour": "Dans une heure",
@@ -398,29 +446,52 @@
"setGenClearSeconds": "Dans {} secondes",
"setGenClearMinute": "Dans une minute",
"setGenMinInstead": "Réduire l'application au lieu de fermer",
"setGenMinOnFieldCopy": "Réduire sur copie d'un champ",
"setGenLock": "Verrou Auto",
"setGenLockMinimize": "quand l'appli est minimisée",
"setGenLockMinimize": "quand l'appli est en arrière-plan",
"setGenLockCopy": "sur copie de m.d.p.",
"setGenLockAutoType": "sur saisie auto",
"setGenLockOrSleep": "Quand l'ordinateur est verrouillé ou mis en sommeil",
"setGenStorage": "Stockage",
"setGenDisableOfflineStorage": "Ne pas mettre en cache des fichiers d'un stockage offline",
"setGenShortLivedStorageToken": "Utiliser des sessions de courte-durée avec les fournisseurs de stockage dans le cloud",
"setGenStorageLogout": "Déconnexion",
"setGenShowAdvanced": "Afficher les paramètres avancés",
"setGenDevTools": "Afficher les outils de développement",
"setGenTryBeta": "Essayer une fois la version beta ",
"setGenTryBetaWarning": "Fichiers non sauvegardés",
"setGenTryBetaWarningBody": "Sauvegarder tous les fichiers et re-cliquer ce bouton",
"setGenShowAppLogs": "Voir les logs",
"setGenReloadApp": "Recharger l'application",
"setGenFieldLabelDblClickAutoType": "Remplissage auto par double clic sur les noms de champ",
"setGenTouchId": "Touch ID",
"setGenTouchIdDisabled": "Ne pas utiliser Touch ID",
"setGenTouchIdMemory": "Dévérouiller avec Touch ID uniquement quand KeeWeb est lancé",
"setGenTouchIdFile": "Toujours utiliser Touch ID à la place du mot de passe",
"setGenTouchIdPass": "Exige le mot de passe après",
"setGenAudit": "Audit",
"setGenAuditPasswords": "Voir des avertissements sur la force du mot de passe",
"setGenAuditPasswordEntropy": "Vérifier la longueur et l'aléas du mot de passe",
"setGenExcludePinsFromAudit": "Ne jamais vérifier les codes PIN courts, comme 123456",
"setGenCheckPasswordsOnHIBP": "Vérifier les mots de passe en utilisant un service en ligne {}",
"setGenHelpHIBP": "KeeWeb peut vérifier si vos mots de passes ont été précédemment exposés à une faille de sécurité en utilisant un service en ligne. Votre mot de passe ne peut pas être récupéré à partir de données envoyées en ligne, cependant le nombre de mots de passes vérifiés peut être exposé. Plus d'informations sur votre sécurité en utilisant ce service peuvent être trouvées {}. Si cette option est activée, KeeWeb vérifiera automatiquement vos mots de passes là.",
"setGenHelpHIBPLink": "ici",
"setGenAuditPasswordAge": "Vieux mots de passe",
"setGenAuditPasswordAgeOff": "Ne pas afficher d'avertissements à propos des vieux mots de passe",
"setGenAuditPasswordAgeOneYear": "Afficher des avertissements pour les mots de passe plus vieux qu'un an",
"setGenAuditPasswordAgeYears": "Afficher des avertissement pour les mots de passe plus vieux que {} ans",
"setFilePath": "Chemin",
"setFileStorage": "Le fichier est ouvert de {}.",
"setFileIntl": "Le fichier est stocké en interne de l'appli",
"setFileIntl": "Le fichier est conservé dans le stockage interne de l'application",
"setFileLocalHint": "Voulez-vous travailler avec des fichiers locaux ?",
"setFileDownloadApp": "Télécharger l'application",
"setFileSave": "Enregistrer",
"setFileSaveTo": "Enregistrer sous",
"setFileSaveTo": "Enregistrer sous...",
"setFileClose": "Fermer",
"setFileSync": "Sync",
"setFileSyncVerb": "Synchroniser",
"setFileSaveToXml": "XML",
"setFileSaveToHtml": "HTML",
"setFileLastSync": "Dernière synchro",
"setFileLastSyncUnknown": "inconnu",
"setFileSyncInProgress": "synchronisation en cours",
@@ -433,8 +504,12 @@
"setFileKeyFile": "Fichier clé",
"setFileSelKeyFile": "Sélectionner fichier clé",
"setFileNames": "Noms",
"setFileDefUser": "Nom par défaut",
"setFileDefUser": "Utilisateur par défaut",
"setFileEnableTrash": "Activer corbeille",
"setFileHistMode": "Historique",
"setFileHistLimited": "Supprimer les anciens enregistrements automatiquement",
"setFileHistDisabled": "Ne pas sauvegarder l'historique",
"setFileHistUnlimited": "Garder les enregistrements de l'historique pour toujours",
"setFileHistLen": "Longueur de l'historique, conserve les derniers enregistrements",
"setFileHistSize": "Taille de l'historique, Mo par fichier",
"setFileBackups": "Sauvegardes",
@@ -458,13 +533,13 @@
"setFileKdfParamsMem": "Mémoire, Ko",
"setFileKdfParamsPar": "Parallèlisme",
"setFileKeyChangeForce": "Demander à changer la clé après (jours)",
"setFileUseKeyFile": "Utiliser fichier clé",
"setFileUseGenKeyFile": "Utiliser fichier clé généré",
"setFileUseOldKeyFile": "Utiliser ancien fichier clé",
"setFileGenKeyFile": "Générer nouveau fichier clé",
"setFileDontUseKeyFile": "Ne pas utiliser fichier clé",
"setFileUseKeyFile": "Utiliser un fichier clé",
"setFileUseGenKeyFile": "Utiliser le fichier clé généré",
"setFileUseOldKeyFile": "Utiliser l'ancien fichier clé",
"setFileGenKeyFile": "Générer un nouveau fichier clé",
"setFileDontUseKeyFile": "Ne pas utiliser de fichier clé",
"setFileEmptyPass": "Mot de passe vide",
"setFileEmptyPassBody": "Sauvegarder la base de données avec un mode de passe vide la laisse sans aucune protection. Voulez-vous vraiment faire cela ?",
"setFileEmptyPassBody": "Sauvegarder la base de données avec un mot de passe vide la laisse sans aucune protection. Voulez-vous vraiment faire cela ?",
"setFileSaveError": "Erreur sauvegarde",
"setFileSaveErrorBody": "Erreur sauvegarde dans le fichier",
"setFileAlreadyExists": "Existe déjà",
@@ -473,6 +548,17 @@
"setFileUnsavedBody": "Il y a des modifications non sauvegardées dans ce fichier",
"setFileCloseNoSave": "Fermer et perdre les modifs",
"setFileDontClose": "Ne pas fermer",
"setFileFormatVersion": "Format de fichier",
"setFileExportRaw": "Exporter vos mots de passe",
"setFileExportRawBody": "Le fichier exporté contiendra vos mots de passe, il n'y seront plus cryptés. Voulez vous continuer ?",
"setFileDeviceIntro": "Les codes à usage unique de cette {} vont être affichés dans l'application.",
"setFileDeviceSettings": "Paramètres",
"setFileYubiKey": "YubiKey",
"setFileDontUseYubiKey": "Ne pas utiliser une YubiKey",
"setFileRefreshYubiKeyList": "Rafraichir la liste",
"setFileYubiKeyHeader": "YubiKey",
"setFileYubiKeyBody": "Utiliser une YubiKey comme partie de la clé maitre est dangeureux, et vous risquez de perdre l'accès à vos mots de passe si quelque chose tourne mal. Avez vous réalisé une sauvegarde de votre fichier avant de modifier les paramètres ?",
"setFileYubiKeyErrorEmptyMac": "Il semble qu'il y a une YubiKey connectée, mais elle est invisible. KeeWeb doit avoir été autorisé dans la section \"Surveillance de l’entrée\" des paramètres de sécurité pour se connecter à la YubiKey.",
"setShTitle": "Raccourcis",
"setShShowAll": "montrer tout",
"setShColors": "montrer les champs en couleur",
@@ -490,11 +576,14 @@
"setShSave": "sauver tous les fichiers",
"setShGen": "générer un mot de passe",
"setShSet": "paramètres",
"setShCopyPassGlobal": "copier le mot de passe (quand l'appli est en arrière-plan)",
"setShCopyUserGlobal": "copier l'utilisateur (quand l'appli est en arrière-plan)",
"setShCopyUrlGlobal": "copier le site web (quand l'appli est en arrière-plan)",
"setShAutoTypeGlobal": "saisie automatique (quand l'appli est en arrière-plan)",
"setShCopyPassGlobal": "copier le mot de passe",
"setShCopyOtp": "Copier l'OTP",
"setShAutoTypeGlobal": "saisie automatique",
"setShCopyPassOnly": "Copier mot de passe",
"setShRestoreApp": "Ouvrir {}",
"setShGlobal": "Ces raccourcis à l'échelle du système fonctionnent lorsque l'application s'exécute en arrière-plan. Vous pouvez cliquer dessus pour sélectionner votre propre raccourci.",
"setShLock": "verrouiller la base",
"setShEdit": "Appuyez sur une nouvelle combinaison de touches pour la définir comme raccourci.",
"setPlInstallTitle": "Installer de nouveaux modules",
"setPlInstallDesc": "Les modules (plugins) de KeeWeb ajoutent des fonctionnalités, thèmes et langues à KeeWeb. Les modules sont lancés avec les même privilèges que KeeWeb : ils peuvent accéder et gérer tous vos mots de passe. Ne jamais installer de modules auxquels vous ne faites pas confiance.",
"setPlInstallLabel": "URL du module",
@@ -525,10 +614,30 @@
"setPlTranslateLink": "traduire l'appli dans votre langue",
"setPlAutoUpdate": "Mise à jour automatique",
"setPlLoadGallery": "Charger le catalogue",
"setAboutTitle": "A propos",
"setDevicesTitle": "Appareils",
"setDevicesEnableUsb": "Autoriser les interactions avec les appareils USB",
"setDevicesYubiKeyIntro": "Il est recommandé de lire {} avant d'utiliser une YubiKey.",
"setDevicesYubiKeyIntroLink": "ce document",
"setDevicesYubiKeyToolsDesc": "Pour permettre l'utilisation de YubiKey dans ce mode, vous devez installer un outil appelé {}.",
"setDevicesYubiKeyToolsDesc2": "{} pour avoir plus d'information sur cet outil.",
"setDevicesYubiKeyToolsDescLink": "Cliquez ici",
"setDevicesYubiKeyToolsStatusChecking": "Vérification si {} est installé",
"setDevicesYubiKeyToolsStatusOk": "{} est installé",
"setDevicesYubiKeyToolsStatusError": "{} n'est pas installé, ou ne fonctionne pas",
"setDevicesYubiKeyOtpTitle": "Codes à usage unique",
"setDevicesYubiKeyOtpDesc": "YubiKey peut être utilisé pour générer des codes à usage unique pour différents services.",
"setDevicesYubiKeyOtpShowIcon": "Afficher l'icône sur l'écran de démarrage",
"setDevicesYubiKeyOtpAutoOpen": "Charger automatiquement les codes à usage unique lorsqu'il y a des fichiers ouverts",
"setDevicesYubiKeyOtpMatchEntries": "Afficher les codes à usage unique qui correspondent dans les entrées",
"setDevicesYubiKeyChalRespTitle": "Challenge-Réponse",
"setDevicesYubiKeyChalRespDesc": "Il est aussi possible d'utiliser une YubiKey en mode Challenge-Réponse, afin qu'une partie de la clé privée utilisée pour crypter les fichiers provienne d'une YubiKey.",
"setDevicesYubiKeyChalRespShow": "Proposer l'option d'utiliser une YubiKey à l'ouverture des fichiers",
"setDevicesYubiKeyStuckWorkaround": "Reconnecter la YubiKey si elle semble bloquée au moment du chargement",
"setDevicesYubiKeyRememberChalResp": "Se souvenir du challenge-réponse le temps que l'application reste ouverte",
"setAboutTitle": "À propos",
"setAboutBuilt": "Cette appli est construite avec ces outils géniaux",
"setAboutLic": "Licence",
"setAboutLicComment": "Cette application et tous les composants qu'elle contient qui ne sont pas dans le domaine public sont sous licence MIT",
"setAboutLicComment": "Cette application et tous les composants qu'elle contient qui ne sont pas dans le domaine public sont sous licence MIT, sauf si autrement spécifié",
"setAboutFirst": "Ceci est une application open-source créée par {}",
"setAboutSecond": " et sous licence {}.",
"setAboutSource": "Le code source et les problèmes sont sur {}.",
@@ -538,7 +647,7 @@
"setHelpProblems1": "Si quelque chose ne va pas, merci de {}",
"setHelpProblems2": "ou {}",
"setHelpOpenIssue": "faire connaître le problème sur GitHub",
"setHelpContactLink": "contacter directement un développeur",
"setHelpContactLink": "contactez le développeur directement",
"setHelpAppInfo": "Information",
"setHelpOtherPlatforms": "Autres plateformes",
"setHelpDesktopApps": "Applis Desktop",
@@ -548,8 +657,11 @@
"dropboxSetupDesc": "Une configuration particulière est nécessaire pour utiliser Dropbox dans une application auto-hébergée. Merci de créer votre propre application Dropbox et d'inscrire sa clé ci-dessous.",
"dropboxAppKey": "Clé Dropbox",
"dropboxAppKeyDesc": "Copier la clé de votre appli Dropbox (Réglages développeur)",
"dropboxAppKeyHint": "Votre \"Dropbox App Key\"",
"dropboxAppSecret": "Votre \"Dropbox App Secret\"",
"dropboxAppSecretDesc": "Votre \"Dropbox App Secret\" peut être trouvée à côté de votre \"Dropbox App Key\".",
"dropboxFolder": "Dossier Appli",
"dropboxFolderDesc": "Si votre appli est lié à Dropbox (pas un dossier), définir le dossier avec vos fichiers Kdbx içi",
"dropboxFolderDesc": "Si votre appli est liée à l'espace Dropbox entier (et non un dossier), définir le dossier avec vos fichiers Kdbx ici",
"dropboxFolderSettingsDesc": "Sélectionner un dossier dans votre Dropbox où les fichiers sont stockés (à la racine par défaut)",
"dropboxFolderPlaceholder": "dossier par défaut",
"dropboxLink": "Lier l'appli à",
@@ -558,10 +670,32 @@
"dropboxLinkCustom": "Votre appli Dropbox",
"gdriveSharedWithMe": "Partagé avec moi",
"webdavSaveMethod": "Méthode de sauvegarde",
"webdavSaveMove": "Uploader un fichier temporaire et le déplacer",
"webdavSavePut": "Ecraser le fichier kdbx avec PUT",
"webdavSaveMove": "Envoyer un fichier temporaire et le déplacer",
"webdavSavePut": "Écraser le fichier kdbx avec PUT",
"webdavNoLastModified": "L'entête HTTP \"Last-Modified\" est absent",
"webdavStatReload": "Toujours recharger le fichier au lieu de se fier à l'entête HTTP \"Last-Modified\"",
"launcherSave": "Sauvegarder base des mots de passe",
"launcherFileFilter": "Fichiers Keepass",
"authPopupRequired": "Les pop-up sont bloquées",
"authPopupRequiredBody": "Merci d'autoriser les popups pour cette appli dans votre navigateur ou essayez à nouveau."
"authPopupRequiredBody": "Merci d'autoriser les pop-ups pour cette appli dans votre navigateur ou essayez à nouveau.",
"exportFileInfo": "Propriétés du fichier",
"exportHtmlName": "Nom",
"exportHtmlDate": "Date d'exportation",
"exportGenerator": "Logiciel",
"exportDescription": "Ce fichier est généré par {}.",
"importCsvTitle": "Import depuis un CSV",
"importCsvRun": "Importer",
"importIgnoreField": "Ignorer",
"importTo": "Les entrées seront importées dans",
"importNewFile": "Nouveau fichier",
"yubiKeyStuckError": "La YubiKey semble coincée, la réparation automatique est activable dans les paramètres de l'application.",
"yubiKeyNoKeyHeader": "Une YubiKey est requise",
"yubiKeyNoKeyBody": "Merci d'insérer votre YubiKey avec le numéro de série {}",
"yubiKeySlot": "port",
"yubiKeyTouchRequestedHeader": "Touchez votre YubiKey",
"yubiKeyTouchRequestedBody": "Merci de toucher votre YubiKey avec le numéro de série {}",
"yubiKeyDisabledErrorHeader": "L'USB est désactivé",
"yubiKeyDisabledErrorBody": "Yubikey est nécessaire pour ouvrir ce fichier, merci d'activer les appareils USB dans les paramètres",
"yubiKeyErrorWithCode": "Erreur Yubikey code {}.",
"bioOpenAuthPrompt": "ouvrir \"{}\""
}
-10
View File
@@ -1,10 +0,0 @@
CACHE MANIFEST
# YYYY-MM-DD:v0.0.0
# updmin:v0.0.0
CACHE:
index.html
NETWORK:
*
+19 -19
View File
@@ -1,21 +1,21 @@
{
"name": "KeeWeb",
"short_name": "KeeWeb",
"description": "Free cross-platform password manager compatible with KeePass",
"display": "standalone",
"orientation": "any",
"theme_color": "#6386ec",
"background_color": "#6386ec",
"icons": [
{
"src": "icons/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "icons/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
]
"name": "KeeWeb",
"short_name": "KeeWeb",
"description": "Free cross-platform password manager compatible with KeePass",
"start_url": "./",
"display": "standalone",
"theme_color": "#6386ec",
"background_color": "#6386ec",
"icons": [
{
"src": "icons/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "icons/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}
Binary file not shown.
+9
View File
@@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyZAmWXMpKsh9WCyUO5TR
2/QIJsgyaViWRAgY5nHZhTR/sjhfG97OeurW7NYC4XPsnyJDepEjDsj9LNzquMES
xsLRSmxo+m1lVWn8Q59LwqOvUK+BKH4eZYF89Nwv2HZjZnr/w7xYcxJbhOuAzpbq
FD/gAvlozrsHG9uI95h1FHPd6mfolEHLK30LXPQ5FdJ/AWb29ILKYbVEdM8qsjoN
fSICw7XTbd7wB0TMcgRpjWllzKaftxCO38svhBjAz4cUvtZ05yi4dzK0VsJHfW33
uno3YBn0/bwLkqMzD1/Hv05p6CVzuDTOCBsXkEobra8OBviatoSukot6cS4Famki
9QIDAQAB
-----END PUBLIC KEY-----
+7 -7
View File
@@ -1,9 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0oZB2Kt7AzRFNqf8FuO3
C3kepHPAIQYiDPYdQxHcsiaFCwyKVx6K1cE/3vBhb8/2rj+QIIWNfAAuu1Y+2VK9
0ZBeq6HciukWzQRO/HWhfdy0c7JwDAslmyGI5olj0ZQkNLhkde1MiMxjDPpRhZtd
JaryVO5cFJaJESpv3dV6m0qXsaQCluWYOSNfSjP9C8o2zRVjSi3ZQZnZIV5pnk9K
2MtlZIPXrN9iJiM5zZ9DTSnqApI6dC9mX4R3LvGN+GTovm9C8Crl+qb106nGRR3L
cweicDnPyMtZLa/E0DBpWYxUVLDp6WeLhxoUBr+6+t3Xp9IDnPoANDQXJXD0f1vQ
xQIDAQAB
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnRq2k3TTx0ewTe6wDr6Q
VeB5diwiIWzsJD+ApfZu1KNPedcAgslAfjpNsYF1if6cYsPMJH70xJ2np6RQBl1V
PdwShOuxkD7m0BD5Hw/Aar8Hdp5cvAdOOMdBO+0DbGeUMy+z66s+oUCJmqVp19T6
PkkxbhN08rgtT7v+aFvrbqbO/vlsskbJpH2K2io+e1XmRGPnSr9q4KSqfGbTfe5g
LwDIOFd66Z4mb5Utb5wWpsy6Gjh06Yf257AccGD3A1bkTNOyeeX0tqciYBePWMk0
icP/aZ6hnErfhnUKf3tOgPLppSHiGcaSKekhChZ2xLUs3U64JwrXSmwHj+TzdO3S
0QIDAQAB
-----END PUBLIC KEY-----
-166
View File
@@ -1,166 +0,0 @@
const Backbone = require('backbone');
const AppModel = require('./models/app-model');
const AppView = require('./views/app-view');
const AppSettingsModel = require('./models/app-settings-model');
const UpdateModel = require('./models/update-model');
const RuntimeDataModel = require('./models/runtime-data-model');
const FileInfoCollection = require('./collections/file-info-collection');
const KeyHandler = require('./comp/key-handler');
const IdleTracker = require('./comp/idle-tracker');
const PopupNotifier = require('./comp/popup-notifier');
const SingleInstanceChecker = require('./comp/single-instance-checker');
const AppRightsChecker = require('./comp/app-rights-checker');
const Alerts = require('./comp/alerts');
const Updater = require('./comp/updater');
const AuthReceiver = require('./comp/auth-receiver');
const ExportApi = require('./comp/export-api');
const SettingsManager = require('./comp/settings-manager');
const PluginManager = require('./plugins/plugin-manager');
const Launcher = require('./comp/launcher');
const FeatureTester = require('./comp/feature-tester');
const FocusDetector = require('./comp/focus-detector');
const Timeouts = require('./const/timeouts');
const FeatureDetector = require('./util/feature-detector');
const KdbxwebInit = require('./util/kdbxweb-init');
const Locale = require('./util/locale');
const ready = Launcher && Launcher.ready || $;
ready(() => {
if (AuthReceiver.receive() || FeatureDetector.isFrame) {
return;
}
loadMixins();
const appModel = new AppModel();
Promise.resolve()
.then(loadConfigs)
.then(initModules)
.then(loadRemoteConfig)
.then(ensureCanRun)
.then(showApp)
.then(postInit)
.catch(e => {
appModel.appLogger.error('Error starting app', e);
});
function loadMixins() {
require('./mixins/view');
require('./helpers');
}
function ensureCanRun() {
return FeatureTester.test()
.catch(e => {
Alerts.error({
header: Locale.appSettingsError,
body: Locale.appNotSupportedError + '<br/><br/>' + e,
buttons: [],
esc: false, enter: false, click: false
});
throw 'Feature testing failed: ' + e;
});
}
function loadConfigs() {
return Promise.all([
AppSettingsModel.instance.load(),
UpdateModel.instance.load(),
RuntimeDataModel.instance.load(),
FileInfoCollection.instance.load()
]);
}
function initModules() {
KeyHandler.init();
IdleTracker.init();
PopupNotifier.init();
KdbxwebInit.init();
FocusDetector.init();
window.kw = ExportApi;
return PluginManager.init();
}
function showSettingsLoadError() {
Alerts.error({
header: Locale.appSettingsError,
body: Locale.appSettingsErrorBody,
buttons: [],
esc: false, enter: false, click: false
});
}
function loadRemoteConfig() {
return Promise.resolve().then(() => {
SettingsManager.setBySettings(appModel.settings);
const configParam = getConfigParam();
if (configParam) {
return appModel.loadConfig(configParam).then(() => {
SettingsManager.setBySettings(appModel.settings);
}).catch(e => {
if (!appModel.settings.get('cacheConfigSettings')) {
showSettingsLoadError();
throw e;
}
});
}
});
}
function showApp() {
return Promise.resolve()
.then(() => {
const skipHttpsWarning = localStorage.skipHttpsWarning || appModel.settings.get('skipHttpsWarning');
const protocolIsInsecure = ['https:', 'file:', 'app:'].indexOf(location.protocol) < 0;
const hostIsInsecure = location.hostname !== 'localhost';
if (protocolIsInsecure && hostIsInsecure && !skipHttpsWarning) {
return new Promise(resolve => {
Alerts.error({
header: Locale.appSecWarn, icon: 'user-secret', esc: false, enter: false, click: false,
body: Locale.appSecWarnBody1 + '<br/><br/>' + Locale.appSecWarnBody2,
buttons: [
{result: '', title: Locale.appSecWarnBtn, error: true}
],
complete: () => {
showView();
resolve();
}
});
});
} else {
showView();
}
});
}
function postInit() {
Updater.init();
SingleInstanceChecker.init();
AppRightsChecker.init();
setTimeout(() => PluginManager.runAutoUpdate(), Timeouts.AutoUpdatePluginsAfterStart);
}
function showView() {
appModel.prepare();
new AppView({ model: appModel }).render();
Backbone.trigger('app-ready');
logStartupTime();
}
function logStartupTime() {
const time = Math.round(performance.now());
appModel.appLogger.info(`Started in ${time}ms ¯\\_(ツ)_/¯`);
}
function getConfigParam() {
const metaConfig = document.head.querySelector('meta[name=kw-config]');
if (metaConfig && metaConfig.content && metaConfig.content[0] !== '(') {
return metaConfig.content;
}
const match = location.search.match(/[?&]config=([^&]+)/i);
if (match && match[1]) {
return match[1];
}
}
});
@@ -1,13 +0,0 @@
const Launcher = require('../comp/launcher');
const AutoTypeEmitterFactory = {
create: function(callback) {
if (Launcher && Launcher.autoTypeSupported) {
const AutoTypeEmitter = require('./emitter/auto-type-emitter-' + Launcher.platform());
return new AutoTypeEmitter(callback);
}
return null;
}
};
module.exports = AutoTypeEmitterFactory;
+160
View File
@@ -0,0 +1,160 @@
import { Features } from 'util/features';
import { NativeModules } from 'comp/launcher/native-modules';
import { Logger } from 'util/logger';
import { Launcher } from 'comp/launcher';
import { Timeouts } from 'const/timeouts';
const logger = new Logger('auto-type-emitter');
const KeyMap = {
tab: 'Tab',
enter: 'Return',
space: 'Space',
up: 'UpArrow',
down: 'DownArrow',
left: 'LeftArrow',
right: 'RightArrow',
home: 'Home',
end: 'End',
pgup: 'PageUp',
pgdn: 'PageDown',
ins: 'Insert',
del: 'ForwardDelete',
bs: 'BackwardDelete',
esc: 'Escape',
win: 'Meta',
rwin: 'RightMeta',
f1: 'F1',
f2: 'F2',
f3: 'F3',
f4: 'F4',
f5: 'F5',
f6: 'F6',
f7: 'F7',
f8: 'F8',
f9: 'F9',
f10: 'F10',
f11: 'F11',
f12: 'F12',
f13: 'F13',
f14: 'F14',
f15: 'F15',
f16: 'F16',
add: 'KeypadPlus',
subtract: 'KeypadMinus',
multiply: 'KeypadMultiply',
divide: 'KeypadDivide',
n0: 'D0',
n1: 'D1',
n2: 'D2',
n3: 'D3',
n4: 'D4',
n5: 'D5',
n6: 'D6',
n7: 'D7',
n8: 'D8',
n9: 'D9'
};
const ModMap = {
'^': Features.isMac ? 'Command' : 'Ctrl',
'+': 'Shift',
'%': 'Alt',
'^^': 'Ctrl'
};
class AutoTypeEmitter {
constructor(callback) {
this.callback = callback;
this.mod = {};
}
begin() {
this.withCallback(NativeModules.kbdEnsureModifierNotPressed());
}
setMod(mod, enabled) {
const nativeMod = ModMap[mod];
if (!nativeMod) {
return this.callback(`Bad modifier: ${mod}`);
}
NativeModules.kbdKeyMoveWithModifier(!!enabled, [nativeMod]).catch((e) => {
logger.error('Error moving modifier', mod, enabled ? 'down' : 'up', e);
});
if (enabled) {
this.mod[nativeMod] = true;
} else {
delete this.mod[nativeMod];
}
}
text(str) {
if (!str) {
return this.withCallback(Promise.resolve());
}
const mods = Object.keys(this.mod);
if (mods.length) {
this.withCallback(NativeModules.kbdTextAsKeys(str, mods));
} else {
this.withCallback(NativeModules.kbdText(str));
}
}
key(key) {
const mods = Object.keys(this.mod);
if (typeof key === 'number') {
this.withCallback(NativeModules.kbdKeyPressWithCharacter(0, key, mods));
} else {
if (!KeyMap[key]) {
return this.callback('Bad key: ' + key);
}
const code = KeyMap[key];
this.withCallback(NativeModules.kbdKeyPress(code, mods));
}
}
copyPaste(text) {
setTimeout(() => {
Launcher.setClipboardText(text);
setTimeout(() => {
this.withCallback(NativeModules.kbdShortcut('V'));
}, Timeouts.AutoTypeCopyPaste);
}, Timeouts.AutoTypeCopyPaste);
}
wait(time) {
setTimeout(() => this.withCallback(Promise.resolve()), time);
}
waitComplete() {
this.withCallback(Promise.resolve());
}
setDelay() {
this.callback('Not implemented');
}
withCallback(promise) {
promise
.then(() => {
try {
this.callback();
} catch (err) {
logger.error('Callback error', err);
}
})
.catch((err) => {
const keyPressFailed = err.message === 'Key press failed';
if (keyPressFailed) {
err.keyPressFailed = true;
}
try {
this.callback(err);
} catch (err) {
logger.error('Callback error', err);
}
});
}
}
export { AutoTypeEmitter };
-85
View File
@@ -1,85 +0,0 @@
const EntryCollection = require('../collections/entry-collection');
const Ranking = require('../util/ranking');
const urlPartsRegex = /^(\w+:\/\/)?(?:(?:www|wwws|secure)\.)?([^\/]+)\/?(.*)/;
const AutoTypeFilter = function(windowInfo, appModel) {
this.title = windowInfo.title;
this.url = windowInfo.url;
this.text = '';
this.ignoreWindowInfo = false;
this.appModel = appModel;
};
AutoTypeFilter.prototype.getEntries = function() {
const filter = {
text: this.text,
autoType: true
};
this.prepareFilter();
let entries = this.appModel.getEntriesByFilter(filter)
.map(e => [e, this.getEntryRank(e)]);
if (!this.ignoreWindowInfo) {
entries = entries.filter(e => e[1]);
}
entries = entries.sort((x, y) => x[1] === y[1] ? x[0].title.localeCompare(y[0].title) : y[1] - x[1]);
entries = entries.map(p => p[0]);
return new EntryCollection(entries, {comparator: 'none'});
};
AutoTypeFilter.prototype.hasWindowInfo = function() {
return this.title || this.url;
};
AutoTypeFilter.prototype.prepareFilter = function() {
this.titleLower = this.title ? this.title.toLowerCase() : null;
this.urlLower = this.url ? this.url.toLowerCase() : null;
this.urlParts = this.url ? urlPartsRegex.exec(this.urlLower) : null;
};
AutoTypeFilter.prototype.getEntryRank = function(entry) {
let rank = 0;
if (this.titleLower && entry.title) {
rank += Ranking.getStringRank(
entry.title.toLowerCase(),
this.titleLower
);
}
if (this.urlParts && entry.url) {
const entryUrlParts = urlPartsRegex.exec(entry.url.toLowerCase());
if (entryUrlParts) {
const [, scheme, domain, path] = entryUrlParts;
const [, thisScheme, thisDomain, thisPath] = this.urlParts;
if (domain === thisDomain || thisDomain.indexOf('.' + domain) > 0) {
if (domain === thisDomain) {
rank += 20;
} else {
rank += 10;
}
if (path === thisPath) {
rank += 10;
} else if (path && thisPath) {
if (path.lastIndexOf(thisPath, 0) === 0) {
rank += 5;
} else if (thisPath.lastIndexOf(path, 0) === 0) {
rank += 3;
}
}
if (scheme === thisScheme) {
rank += 1;
}
} else {
if (entry.searchText.indexOf(this.urlLower) >= 0) {
// the url is in some field; include it
rank += 5;
} else {
// another domain; don't show this record at all, ignore title match
return 0;
}
}
}
}
return rank;
};
module.exports = AutoTypeFilter;
@@ -1,13 +0,0 @@
const Launcher = require('../comp/launcher');
const AutoTypeHelperFactory = {
create: function() {
if (Launcher && Launcher.autoTypeSupported) {
const AutoTypeHelper = require('./helper/auto-type-helper-' + Launcher.platform());
return new AutoTypeHelper();
}
return null;
}
};
module.exports = AutoTypeHelperFactory;
+16
View File
@@ -0,0 +1,16 @@
import { NativeModules } from 'comp/launcher/native-modules';
class AutoTypeHelper {
getActiveWindowInfo(callback) {
NativeModules.kbdGetActiveWindow({
getWindowTitle: true,
getBrowserUrl: true
})
.then((win) => {
callback(undefined, win);
})
.catch((err) => callback(err));
}
}
export { AutoTypeHelper };
+28 -25
View File
@@ -1,14 +1,13 @@
const Logger = require('../util/logger');
import { Logger } from 'util/logger';
const logger = new Logger('auto-type-obfuscator');
logger.setLevel(localStorage.autoTypeDebug ? Logger.Level.All : Logger.Level.Warn);
const MaxFakeOps = 30;
const MaxSteps = 1000;
const MaxCopy = 2;
const FakeCharAlphabet = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz123456789O0oIl';
const AutoTypeObfuscator = function(chars) {
const AutoTypeObfuscator = function (chars) {
this.chars = chars;
this.inputChars = [];
this.inputCursor = 0;
@@ -18,7 +17,7 @@ const AutoTypeObfuscator = function(chars) {
this.copyCount = 0;
};
AutoTypeObfuscator.prototype.obfuscate = function() {
AutoTypeObfuscator.prototype.obfuscate = function () {
while (!this.finished()) {
this.step();
if (this.stepCount++ > MaxSteps) {
@@ -32,12 +31,16 @@ AutoTypeObfuscator.prototype.obfuscate = function() {
return this.ops;
};
AutoTypeObfuscator.prototype.finished = function() {
return this.chars.length === this.inputChars.length &&
this.chars.every(function(ch, ix) { return this.inputChars[ix].ch === ch; }, this);
AutoTypeObfuscator.prototype.finished = function () {
return (
this.chars.length === this.inputChars.length &&
this.chars.every(function (ch, ix) {
return this.inputChars[ix].ch === ch;
}, this)
);
};
AutoTypeObfuscator.prototype.step = function() {
AutoTypeObfuscator.prototype.step = function () {
const isFake = this.stepCount < MaxFakeOps && Math.random() > this.stepCount / MaxFakeOps;
if (isFake) {
this.stepFake();
@@ -45,11 +48,11 @@ AutoTypeObfuscator.prototype.step = function() {
this.stepReal();
}
if (logger.getLevel() >= Logger.Level.Debug) {
logger.debug('value', this.inputChars.map(ic => ic.ch).join(''));
logger.debug('value', this.inputChars.map((ic) => ic.ch).join(''));
}
};
AutoTypeObfuscator.prototype.stepFake = function() {
AutoTypeObfuscator.prototype.stepFake = function () {
const pos = Math.floor(Math.random() * (this.inputChars.length + 1));
const ch = FakeCharAlphabet[Math.floor(Math.random() * FakeCharAlphabet.length)];
logger.info('step.fake', pos, ch);
@@ -78,7 +81,7 @@ AutoTypeObfuscator.prototype.stepFake = function() {
}
};
AutoTypeObfuscator.prototype.stepReal = function() {
AutoTypeObfuscator.prototype.stepReal = function () {
const possibleActions = [];
const inputRealPositions = [];
let i;
@@ -106,7 +109,7 @@ AutoTypeObfuscator.prototype.stepReal = function() {
break;
}
}
possibleActions.push({ ins: true, ch: this.chars[i], ix: i, from: from, to: to });
possibleActions.push({ ins: true, ch: this.chars[i], ix: i, from, to });
}
}
const action = possibleActions[Math.floor(Math.random() * possibleActions.length)];
@@ -127,7 +130,7 @@ AutoTypeObfuscator.prototype.stepReal = function() {
}
};
AutoTypeObfuscator.prototype.moveToPos = function(pos) {
AutoTypeObfuscator.prototype.moveToPos = function (pos) {
logger.debug('moveToPos', pos);
while (this.inputCursor > pos) {
this.moveLeft();
@@ -137,47 +140,47 @@ AutoTypeObfuscator.prototype.moveToPos = function(pos) {
}
};
AutoTypeObfuscator.prototype.moveLeft = function() {
AutoTypeObfuscator.prototype.moveLeft = function () {
logger.debug('moveLeft');
this.ops.push({ type: 'key', value: 'left' });
this.inputCursor--;
this.inputSel = 0;
};
AutoTypeObfuscator.prototype.moveRight = function() {
AutoTypeObfuscator.prototype.moveRight = function () {
logger.debug('moveRight');
this.ops.push({ type: 'key', value: 'right' });
this.inputCursor++;
this.inputSel = 0;
};
AutoTypeObfuscator.prototype.inputChar = function(ch) {
AutoTypeObfuscator.prototype.inputChar = function (ch) {
logger.debug('inputChar', ch);
this.ops.push({ type: 'text', value: ch });
this.inputChars.splice(this.inputCursor, this.inputSel, { ch: ch });
this.inputChars.splice(this.inputCursor, this.inputSel, { ch });
this.inputCursor++;
this.inputSel = 0;
};
AutoTypeObfuscator.prototype.copyPaste = function(ch) {
AutoTypeObfuscator.prototype.copyPaste = function (ch) {
logger.debug('copyPaste', ch);
this.ops.push({type: 'cmd', value: 'copyPaste', arg: ch});
this.inputChars.splice(this.inputCursor, this.inputSel, { ch: ch });
this.ops.push({ type: 'cmd', value: 'copyPaste', arg: ch });
this.inputChars.splice(this.inputCursor, this.inputSel, { ch });
this.inputCursor++;
this.inputSel = 0;
};
AutoTypeObfuscator.prototype.selectText = function(backward, count) {
AutoTypeObfuscator.prototype.selectText = function (backward, count) {
logger.debug('selectText', backward ? 'left' : 'right', count);
const ops = [];
for (let i = 0; i < count; i++) {
ops.push({ type: 'key', value: backward ? 'left' : 'right' });
}
if (ops.length === 1) {
ops[0].mod = {'+': true};
ops[0].mod = { '+': true };
this.ops.push(ops[0]);
} else {
this.ops.push({type: 'group', value: ops, mod: {'+': true}});
this.ops.push({ type: 'group', value: ops, mod: { '+': true } });
}
if (backward) {
this.inputCursor -= count;
@@ -185,7 +188,7 @@ AutoTypeObfuscator.prototype.selectText = function(backward, count) {
this.inputSel = count;
};
AutoTypeObfuscator.prototype.deleteText = function(backward) {
AutoTypeObfuscator.prototype.deleteText = function (backward) {
logger.debug('deleteText', backward ? 'left' : 'right');
this.ops.push({ type: 'key', value: backward ? 'bs' : 'del' });
if (this.inputSel) {
@@ -199,4 +202,4 @@ AutoTypeObfuscator.prototype.deleteText = function(backward) {
}
};
module.exports = AutoTypeObfuscator;
export { AutoTypeObfuscator };
+15 -15
View File
@@ -1,6 +1,6 @@
const AutoTypeRunner = require('./auto-type-runner');
import { AutoTypeRunner } from 'auto-type/auto-type-runner';
const AutoTypeParser = function(sequence) {
const AutoTypeParser = function (sequence) {
this.sequence = sequence;
this.ix = 0;
this.states = [];
@@ -8,7 +8,7 @@ const AutoTypeParser = function(sequence) {
AutoTypeParser.opRegex = /^(.*?)(?:([\s:=])[\s:=]*(.*))?$/;
AutoTypeParser.prototype.parse = function() {
AutoTypeParser.prototype.parse = function () {
const len = this.sequence.length;
this.pushState();
while (this.ix < len) {
@@ -45,14 +45,14 @@ AutoTypeParser.prototype.parse = function() {
return new AutoTypeRunner(this.state().ops);
};
AutoTypeParser.prototype.pushState = function() {
AutoTypeParser.prototype.pushState = function () {
this.states.unshift({
modifiers: null,
ops: []
});
};
AutoTypeParser.prototype.popState = function() {
AutoTypeParser.prototype.popState = function () {
if (this.states.length <= 1) {
throw 'Unexpected ")" at index ' + this.ix;
}
@@ -60,11 +60,11 @@ AutoTypeParser.prototype.popState = function() {
this.addState(state);
};
AutoTypeParser.prototype.state = function() {
AutoTypeParser.prototype.state = function () {
return this.states[0];
};
AutoTypeParser.prototype.readOp = function() {
AutoTypeParser.prototype.readOp = function () {
const toIx = this.sequence.indexOf('}', this.ix + 2);
if (toIx < 0) {
throw 'Mismatched "{" at index ' + this.ix;
@@ -79,7 +79,7 @@ AutoTypeParser.prototype.readOp = function() {
this.addOp(op, sep, arg);
};
AutoTypeParser.prototype.readModifier = function(modifier) {
AutoTypeParser.prototype.readModifier = function (modifier) {
const state = this.state();
if (!state.modifiers) {
state.modifiers = {};
@@ -91,14 +91,14 @@ AutoTypeParser.prototype.readModifier = function(modifier) {
state.modifiers[modifier] = true;
};
AutoTypeParser.prototype.resetModifiers = function() {
AutoTypeParser.prototype.resetModifiers = function () {
const state = this.state();
const modifiers = state.modifiers;
state.modifiers = null;
return modifiers;
};
AutoTypeParser.prototype.addState = function(state) {
AutoTypeParser.prototype.addState = function (state) {
this.state().ops.push({
type: 'group',
value: state.ops,
@@ -106,7 +106,7 @@ AutoTypeParser.prototype.addState = function(state) {
});
};
AutoTypeParser.prototype.addChar = function(ch) {
AutoTypeParser.prototype.addChar = function (ch) {
this.state().ops.push({
type: 'text',
value: ch,
@@ -114,14 +114,14 @@ AutoTypeParser.prototype.addChar = function(ch) {
});
};
AutoTypeParser.prototype.addOp = function(op, sep, arg) {
AutoTypeParser.prototype.addOp = function (op, sep, arg) {
this.state().ops.push({
type: 'op',
value: op,
mod: this.resetModifiers(),
sep: sep,
arg: arg
sep,
arg
});
};
module.exports = AutoTypeParser;
export { AutoTypeParser };
+197 -89
View File
@@ -1,12 +1,11 @@
const AutoTypeObfuscator = require('./auto-type-obfuscator');
const AutoTypeEmitterFactory = require('./auto-type-emitter-factory');
const Format = require('../util/format');
const Logger = require('../util/logger');
import { AutoTypeEmitter } from 'auto-type/auto-type-emitter';
import { AutoTypeObfuscator } from 'auto-type/auto-type-obfuscator';
import { StringFormat } from 'util/formatting/string-format';
import { Logger } from 'util/logger';
const emitterLogger = new Logger('auto-type-emitter');
emitterLogger.setLevel(localStorage.autoTypeDebug ? Logger.Level.All : Logger.Level.Warn);
const AutoTypeRunner = function(ops) {
const AutoTypeRunner = function (ops) {
this.ops = ops;
this.pendingResolvesCount = 0;
this.entry = null;
@@ -16,43 +15,132 @@ const AutoTypeRunner = function(ops) {
AutoTypeRunner.PendingResolve = { pending: true };
AutoTypeRunner.Keys = {
tab: 'tab', enter: 'enter', space: 'space',
up: 'up', down: 'down', left: 'left', right: 'right', home: 'home', end: 'end', pgup: 'pgup', pgdn: 'pgdn',
insert: 'ins', ins: 'ins', delete: 'del', del: 'del', backspace: 'bs', bs: 'bs', bksp: 'bs', esc: 'esc',
win: 'win', lwin: 'win', rwin: 'rwin', f1: 'f1', f2: 'f2', f3: 'f3', f4: 'f4', f5: 'f5', f6: 'f6',
f7: 'f7', f8: 'f8', f9: 'f9', f10: 'f10', f11: 'f11', f12: 'f12', f13: 'f13', f14: 'f14', f15: 'f15', f16: 'f16',
add: 'add', subtract: 'subtract', multiply: 'multiply', divide: 'divide',
numpad0: 'n0', numpad1: 'n1', numpad2: 'n2', numpad3: 'n3', numpad4: 'n4',
numpad5: 'n5', numpad6: 'n6', numpad7: 'n7', numpad8: 'n8', numpad9: 'n9'
tab: 'tab',
enter: 'enter',
space: 'space',
up: 'up',
down: 'down',
left: 'left',
right: 'right',
home: 'home',
end: 'end',
pgup: 'pgup',
pgdn: 'pgdn',
insert: 'ins',
ins: 'ins',
delete: 'del',
del: 'del',
backspace: 'bs',
bs: 'bs',
bksp: 'bs',
esc: 'esc',
win: 'win',
lwin: 'win',
rwin: 'rwin',
f1: 'f1',
f2: 'f2',
f3: 'f3',
f4: 'f4',
f5: 'f5',
f6: 'f6',
f7: 'f7',
f8: 'f8',
f9: 'f9',
f10: 'f10',
f11: 'f11',
f12: 'f12',
f13: 'f13',
f14: 'f14',
f15: 'f15',
f16: 'f16',
add: 'add',
subtract: 'subtract',
multiply: 'multiply',
divide: 'divide',
numpad0: 'n0',
numpad1: 'n1',
numpad2: 'n2',
numpad3: 'n3',
numpad4: 'n4',
numpad5: 'n5',
numpad6: 'n6',
numpad7: 'n7',
numpad8: 'n8',
numpad9: 'n9'
};
AutoTypeRunner.Substitutions = {
title: function(runner, op) { return runner.getEntryFieldKeys('Title', op); },
username: function(runner, op) { return runner.getEntryFieldKeys('UserName', op); },
url: function(runner, op) { return runner.getEntryFieldKeys('URL', op); },
password: function(runner, op) { return runner.getEntryFieldKeys('Password', op); },
notes: function(runner, op) { return runner.getEntryFieldKeys('Notes', op); },
group: function(runner) { return runner.getEntryGroupName(); },
totp: function(runner, op) { return runner.getOtp(op); },
s: function(runner, op) { return runner.getEntryFieldKeys(op.arg, op); },
'dt_simple': function(runner) { return runner.dt('simple'); },
'dt_year': function(runner) { return runner.dt('Y'); },
'dt_month': function(runner) { return runner.dt('M'); },
'dt_day': function(runner) { return runner.dt('D'); },
'dt_hour': function(runner) { return runner.dt('h'); },
'dt_minute': function(runner) { return runner.dt('m'); },
'dt_second': function(runner) { return runner.dt('s'); },
'dt_utc_simple': function(runner) { return runner.udt('simple'); },
'dt_utc_year': function(runner) { return runner.udt('Y'); },
'dt_utc_month': function(runner) { return runner.udt('M'); },
'dt_utc_day': function(runner) { return runner.udt('D'); },
'dt_utc_hour': function(runner) { return runner.udt('h'); },
'dt_utc_minute': function(runner) { return runner.udt('m'); },
'dt_utc_second': function(runner) { return runner.udt('s'); }
title(runner, op) {
return runner.getEntryFieldKeys('Title', op);
},
username(runner, op) {
return runner.getEntryFieldKeys('UserName', op);
},
url(runner, op) {
return runner.getEntryFieldKeys('URL', op);
},
password(runner, op) {
return runner.getEntryFieldKeys('Password', op);
},
notes(runner, op) {
return runner.getEntryFieldKeys('Notes', op);
},
group(runner) {
return runner.getEntryGroupName();
},
totp(runner, op) {
return runner.getOtp(op);
},
s(runner, op) {
return runner.getEntryFieldKeys(op.arg, op);
},
'dt_simple'(runner) {
return runner.dt('simple');
},
'dt_year'(runner) {
return runner.dt('Y');
},
'dt_month'(runner) {
return runner.dt('M');
},
'dt_day'(runner) {
return runner.dt('D');
},
'dt_hour'(runner) {
return runner.dt('h');
},
'dt_minute'(runner) {
return runner.dt('m');
},
'dt_second'(runner) {
return runner.dt('s');
},
'dt_utc_simple'(runner) {
return runner.udt('simple');
},
'dt_utc_year'(runner) {
return runner.udt('Y');
},
'dt_utc_month'(runner) {
return runner.udt('M');
},
'dt_utc_day'(runner) {
return runner.udt('D');
},
'dt_utc_hour'(runner) {
return runner.udt('h');
},
'dt_utc_minute'(runner) {
return runner.udt('m');
},
'dt_utc_second'(runner) {
return runner.udt('s');
}
};
AutoTypeRunner.prototype.resolve = function(entry, callback) {
AutoTypeRunner.prototype.resolve = function (entry, context, callback) {
this.entry = entry;
this.context = context;
try {
this.resolveOps(this.ops);
if (!this.pendingResolvesCount) {
@@ -65,7 +153,7 @@ AutoTypeRunner.prototype.resolve = function(entry, callback) {
}
};
AutoTypeRunner.prototype.resolveOps = function(ops) {
AutoTypeRunner.prototype.resolveOps = function (ops) {
for (let i = 0, len = ops.length; i < len; i++) {
const op = ops[i];
if (op.type === 'group') {
@@ -76,7 +164,7 @@ AutoTypeRunner.prototype.resolveOps = function(ops) {
}
};
AutoTypeRunner.prototype.resolveOp = function(op) {
AutoTypeRunner.prototype.resolveOp = function (op) {
if (op.value.length === 1 && !op.sep) {
// {x}
op.type = 'text';
@@ -103,7 +191,7 @@ AutoTypeRunner.prototype.resolveOp = function(op) {
op.value = [];
const count = +op.arg;
for (let i = 0; i < count; i++) {
op.value.push({type: 'key', value: key});
op.value.push({ type: 'key', value: key });
}
} else {
// {TAB}
@@ -112,6 +200,11 @@ AutoTypeRunner.prototype.resolveOp = function(op) {
}
return;
}
if (this.context?.resolved?.[lowerValue]) {
op.type = 'text';
op.value = this.context.resolved[lowerValue];
return;
}
const substitution = AutoTypeRunner.Substitutions[lowerValue];
if (substitution) {
// {title}
@@ -127,7 +220,7 @@ AutoTypeRunner.prototype.resolveOp = function(op) {
}
};
AutoTypeRunner.prototype.tryParseCommand = function(op) {
AutoTypeRunner.prototype.tryParseCommand = function (op) {
switch (op.value.toLowerCase()) {
case 'clearfield':
// {CLEARFIELD}
@@ -142,7 +235,7 @@ AutoTypeRunner.prototype.tryParseCommand = function(op) {
// {VKEY 10} {VKEY 0x1F}
op.type = 'key';
op.value = parseInt(op.arg);
if (isNaN(op.value) || op.value <= 0) {
if (isNaN(op.value) || op.value < 0) {
throw 'Bad vkey: ' + op.arg;
}
return true;
@@ -166,7 +259,7 @@ AutoTypeRunner.prototype.tryParseCommand = function(op) {
}
};
AutoTypeRunner.prototype.getEntryFieldKeys = function(field, op) {
AutoTypeRunner.prototype.getEntryFieldKeys = function (field, op) {
if (!field || !this.entry) {
return '';
}
@@ -177,11 +270,11 @@ AutoTypeRunner.prototype.getEntryFieldKeys = function(field, op) {
if (value.isProtected) {
op.type = 'group';
const ops = [];
value.forEachChar(ch => {
value.forEachChar((ch) => {
if (ch === 10 || ch === 13) {
ops.push({type: 'key', value: 'enter'});
ops.push({ type: 'key', value: 'enter' });
} else {
ops.push({type: 'text', value: String.fromCharCode(ch)});
ops.push({ type: 'text', value: String.fromCharCode(ch) });
}
});
return ops;
@@ -192,65 +285,79 @@ AutoTypeRunner.prototype.getEntryFieldKeys = function(field, op) {
}
op.type = 'group';
const partsOps = [];
parts.forEach(part => {
parts.forEach((part) => {
if (partsOps.length) {
partsOps.push({type: 'key', value: 'enter'});
partsOps.push({ type: 'key', value: 'enter' });
}
if (part) {
partsOps.push({type: 'text', value: part});
partsOps.push({ type: 'text', value: part });
}
});
return partsOps;
}
};
AutoTypeRunner.prototype.getEntryGroupName = function() {
return this.entry && this.entry.group.get('title');
AutoTypeRunner.prototype.getEntryGroupName = function () {
return this.entry && this.entry.group.title;
};
AutoTypeRunner.prototype.dt = function(part) {
AutoTypeRunner.prototype.dt = function (part) {
switch (part) {
case 'simple':
return this.dt('Y') + this.dt('M') + this.dt('D') + this.dt('h') + this.dt('m') + this.dt('s');
return (
this.dt('Y') +
this.dt('M') +
this.dt('D') +
this.dt('h') +
this.dt('m') +
this.dt('s')
);
case 'Y':
return this.now.getFullYear().toString();
case 'M':
return Format.pad(this.now.getMonth() + 1, 2);
return StringFormat.pad(this.now.getMonth() + 1, 2);
case 'D':
return Format.pad(this.now.getDate(), 2);
return StringFormat.pad(this.now.getDate(), 2);
case 'h':
return Format.pad(this.now.getHours(), 2);
return StringFormat.pad(this.now.getHours(), 2);
case 'm':
return Format.pad(this.now.getMinutes(), 2);
return StringFormat.pad(this.now.getMinutes(), 2);
case 's':
return Format.pad(this.now.getSeconds(), 2);
return StringFormat.pad(this.now.getSeconds(), 2);
default:
throw 'Bad part: ' + part;
}
};
AutoTypeRunner.prototype.udt = function(part) {
AutoTypeRunner.prototype.udt = function (part) {
switch (part) {
case 'simple':
return this.udt('Y') + this.udt('M') + this.udt('D') + this.udt('h') + this.udt('m') + this.udt('s');
return (
this.udt('Y') +
this.udt('M') +
this.udt('D') +
this.udt('h') +
this.udt('m') +
this.udt('s')
);
case 'Y':
return this.now.getUTCFullYear().toString();
case 'M':
return Format.pad(this.now.getUTCMonth() + 1, 2);
return StringFormat.pad(this.now.getUTCMonth() + 1, 2);
case 'D':
return Format.pad(this.now.getUTCDate(), 2);
return StringFormat.pad(this.now.getUTCDate(), 2);
case 'h':
return Format.pad(this.now.getUTCHours(), 2);
return StringFormat.pad(this.now.getUTCHours(), 2);
case 'm':
return Format.pad(this.now.getUTCMinutes(), 2);
return StringFormat.pad(this.now.getUTCMinutes(), 2);
case 's':
return Format.pad(this.now.getUTCSeconds(), 2);
return StringFormat.pad(this.now.getUTCSeconds(), 2);
default:
throw 'Bad part: ' + part;
}
};
AutoTypeRunner.prototype.getOtp = function(op) {
AutoTypeRunner.prototype.getOtp = function (op) {
if (!this.entry) {
return '';
}
@@ -258,13 +365,13 @@ AutoTypeRunner.prototype.getOtp = function(op) {
if (!this.entry.otpGenerator) {
return '';
}
this.entry.otpGenerator.next(otp => {
this.pendingResolved(op, otp, otp ? undefined : 'OTP error');
this.entry.otpGenerator.next((err, otp) => {
this.pendingResolved(op, otp, err);
});
return AutoTypeRunner.PendingResolve;
};
AutoTypeRunner.prototype.pendingResolved = function(op, value, error) {
AutoTypeRunner.prototype.pendingResolved = function (op, value, error) {
const wasPending = op.value === AutoTypeRunner.PendingResolve;
if (value) {
op.value = value;
@@ -279,11 +386,11 @@ AutoTypeRunner.prototype.pendingResolved = function(op, value, error) {
}
};
AutoTypeRunner.prototype.obfuscate = function() {
AutoTypeRunner.prototype.obfuscate = function () {
this.obfuscateOps(this.ops);
};
AutoTypeRunner.prototype.obfuscateOps = function(ops) {
AutoTypeRunner.prototype.obfuscateOps = function (ops) {
for (let i = 0, len = ops.length; i < len; i++) {
const op = ops[i];
if (op.mod) {
@@ -292,7 +399,7 @@ AutoTypeRunner.prototype.obfuscateOps = function(ops) {
if (op.type === 'text') {
this.obfuscateOp(op);
} else if (op.type === 'group') {
const onlyText = op.value.every(grOp => grOp.type === 'text' && !grOp.mod);
const onlyText = op.value.every((grOp) => grOp.type === 'text' && !grOp.mod);
if (onlyText) {
this.obfuscateOp(op);
} else {
@@ -302,7 +409,7 @@ AutoTypeRunner.prototype.obfuscateOps = function(ops) {
}
};
AutoTypeRunner.prototype.obfuscateOp = function(op) {
AutoTypeRunner.prototype.obfuscateOp = function (op) {
let letters = [];
if (op.type === 'text') {
if (!op.value || op.value.length <= 1) {
@@ -310,7 +417,7 @@ AutoTypeRunner.prototype.obfuscateOp = function(op) {
}
letters = op.value.split('');
} else {
op.value.forEach(grOp => letters.push.apply(letters, grOp.value.split('')));
op.value.forEach((grOp) => letters.push(...grOp.value.split('')));
}
if (letters.length <= 1) {
return;
@@ -320,10 +427,10 @@ AutoTypeRunner.prototype.obfuscateOp = function(op) {
op.type = 'group';
};
AutoTypeRunner.prototype.run = function(callback) {
this.emitter = AutoTypeEmitterFactory.create(this.emitNext.bind(this));
AutoTypeRunner.prototype.run = function (callback, windowId) {
this.emitter = new AutoTypeEmitter(this.emitNext.bind(this), windowId);
this.emitterState = {
callback: callback,
callback,
stack: [],
ops: this.ops,
opIx: 0,
@@ -331,10 +438,10 @@ AutoTypeRunner.prototype.run = function(callback) {
activeMod: {},
finished: null
};
this.emitNext();
this.emitter.begin();
};
AutoTypeRunner.prototype.emitNext = function(err) {
AutoTypeRunner.prototype.emitNext = function (err) {
if (err) {
this.emitterState.finished = true;
this.emitterState.callback(err);
@@ -348,7 +455,7 @@ AutoTypeRunner.prototype.emitNext = function(err) {
if (this.emitterState.opIx >= this.emitterState.ops.length) {
const state = this.emitterState.stack.pop();
if (state) {
_.extend(this.emitterState, { ops: state.ops, opIx: state.opIx, mod: state.mod });
Object.assign(this.emitterState, { ops: state.ops, opIx: state.opIx, mod: state.mod });
this.emitNext();
} else {
this.resetEmitterMod({});
@@ -366,12 +473,12 @@ AutoTypeRunner.prototype.emitNext = function(err) {
this.emitterState.stack.push({
ops: this.emitterState.ops,
opIx: this.emitterState.opIx + 1,
mod: _.clone(this.emitterState.mod)
mod: { ...this.emitterState.mod }
});
_.extend(this.emitterState, {
Object.assign(this.emitterState, {
ops: op.value,
opIx: 0,
mod: _.clone(this.emitterState.activeMod)
mod: { ...this.emitterState.activeMod }
});
this.emitNext();
return;
@@ -393,7 +500,7 @@ AutoTypeRunner.prototype.emitNext = function(err) {
emitterLogger.debug('key', op.value);
this.emitter.key(op.value);
break;
case 'cmd':
case 'cmd': {
const method = this.emitter[op.value];
if (!method) {
throw 'Bad cmd: ' + op.value;
@@ -401,13 +508,14 @@ AutoTypeRunner.prototype.emitNext = function(err) {
emitterLogger.debug(op.value, op.arg);
method.call(this.emitter, op.arg);
break;
}
default:
throw 'Bad op: ' + op.type;
}
};
AutoTypeRunner.prototype.setEmitterMod = function(addedMod) {
Object.keys(addedMod).forEach(function(mod) {
AutoTypeRunner.prototype.setEmitterMod = function (addedMod) {
Object.keys(addedMod).forEach(function (mod) {
if (addedMod[mod] && !this.emitterState.activeMod[mod]) {
emitterLogger.debug('mod', mod, true);
this.emitter.setMod(mod, true);
@@ -416,8 +524,8 @@ AutoTypeRunner.prototype.setEmitterMod = function(addedMod) {
}, this);
};
AutoTypeRunner.prototype.resetEmitterMod = function(targetState) {
Object.keys(this.emitterState.activeMod).forEach(function(mod) {
AutoTypeRunner.prototype.resetEmitterMod = function (targetState) {
Object.keys(this.emitterState.activeMod).forEach(function (mod) {
if (this.emitterState.activeMod[mod] && !targetState[mod]) {
emitterLogger.debug('mod', mod, false);
this.emitter.setMod(mod, false);
@@ -426,4 +534,4 @@ AutoTypeRunner.prototype.resetEmitterMod = function(targetState) {
}, this);
};
module.exports = AutoTypeRunner;
export { AutoTypeRunner };
@@ -1,91 +0,0 @@
const Launcher = require('../../comp/launcher');
const AutoTypeNativeHelper = require('../helper/auto-type-native-helper');
// http://eastmanreference.com/complete-list-of-applescript-key-codes/
const KeyMap = {
tab: 48, enter: 36, space: 49,
up: 126, down: 125, left: 123, right: 124, home: 115, end: 119, pgup: 116, pgdn: 121,
ins: 114, del: 117, bs: 51, esc: 53,
win: 55, rwin: 55,
f1: 122, f2: 120, f3: 99, f4: 118, f5: 96, f6: 97, f7: 98, f8: 100, f9: 101,
f10: 109, f11: 103, f12: 111, f13: 105, f14: 107, f15: 113, f16: 106,
add: 69, subtract: 78, multiply: 67, divide: 75,
n0: 82, n1: 83, n2: 84, n3: 85, n4: 86,
n5: 87, n6: 88, n7: 89, n8: 91, n9: 92
};
const ModMap = {
'^': '@',
'+': '+',
'%': '%',
'^^': '^'
};
const AutoTypeEmitter = function(callback) {
this.callback = callback;
this.mod = {};
this.pendingScript = [];
};
AutoTypeEmitter.prototype.setMod = function(mod, enabled) {
if (enabled) {
this.mod[ModMap[mod]] = true;
} else {
delete this.mod[ModMap[mod]];
}
};
AutoTypeEmitter.prototype.text = function(text) {
this.pendingScript.push('text ' + this.modString() + ' ' + text);
this.callback();
};
AutoTypeEmitter.prototype.key = function(key) {
if (typeof key !== 'number') {
if (!KeyMap[key]) {
return this.callback('Bad key: ' + key);
}
key = KeyMap[key];
}
this.pendingScript.push('key ' + this.modString() + key);
this.callback();
};
AutoTypeEmitter.prototype.copyPaste = function(text) {
this.pendingScript.push('copypaste ' + text);
this.callback();
};
AutoTypeEmitter.prototype.wait = function(time) {
this.pendingScript.push('wait ' + time);
this.callback();
};
AutoTypeEmitter.prototype.waitComplete = function() {
if (this.pendingScript.length) {
const script = this.pendingScript.join('\n');
this.pendingScript.length = 0;
this.runScript(script);
} else {
this.callback();
}
};
AutoTypeEmitter.prototype.setDelay = function(delay) {
this.delay = delay || 0;
this.callback('Not implemented');
};
AutoTypeEmitter.prototype.modString = function() {
return Object.keys(this.mod).join('');
};
AutoTypeEmitter.prototype.runScript = function(script) {
Launcher.spawn({
cmd: AutoTypeNativeHelper.getHelperPath(),
data: script,
complete: this.callback
});
};
module.exports = AutoTypeEmitter;
@@ -1,109 +0,0 @@
const Launcher = require('../../comp/launcher');
const Locale = require('../../util/locale');
// https://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h
const KeyMap = {
tab: 'Tab', enter: 'KP_Enter', space: 'KP_Space',
up: 'Up', down: 'Down', left: 'Left', right: 'Right', home: 'Home', end: 'End', pgup: 'Page_Up', pgdn: 'Page_Down',
ins: 'Insert', del: 'Delete', bs: 'BackSpace', esc: 'Escape',
win: 'Meta_L', rwin: 'Meta_R',
f1: 'F1', f2: 'F2', f3: 'F3', f4: 'F4', f5: 'F5', f6: 'F6', f7: 'F7', f8: 'F8', f9: 'F9',
f10: 'F10', f11: 'F11', f12: 'F12', f13: 'F13', f14: 'F14', f15: 'F15', f16: 'F16',
add: 'KP_Add', subtract: 'KP_Subtract', multiply: 'KP_Multiply', divide: 'KP_Divide',
n0: 'KP_0', n1: 'KP_1', n2: 'KP_2', n3: 'KP_3', n4: 'KP_4',
n5: 'KP_5', n6: 'KP_6', n7: 'KP_7', n8: 'KP_8', n9: 'KP_9'
};
const ModMap = {
'^': 'ctrl',
'+': 'shift',
'%': 'alt',
'^^': 'ctrl'
};
const AutoTypeEmitter = function(callback) {
this.callback = callback;
this.mod = {};
this.pendingScript = [];
};
AutoTypeEmitter.prototype.setMod = function(mod, enabled) {
if (enabled) {
this.mod[ModMap[mod]] = true;
} else {
delete this.mod[ModMap[mod]];
}
};
AutoTypeEmitter.prototype.text = function(text) {
this.pendingScript.push('keyup ctrl alt shift t');
Object.keys(this.mod).forEach(mod => {
this.pendingScript.push('keydown ' + ModMap[mod]);
});
text.split('').map(char => {
this.pendingScript.push('key U' + char.charCodeAt(0).toString(16));
});
Object.keys(this.mod).forEach(mod => {
this.pendingScript.push('keyup ' + ModMap[mod]);
});
this.waitComplete();
};
AutoTypeEmitter.prototype.key = function(key) {
if (typeof key !== 'number') {
if (!KeyMap[key]) {
return this.callback('Bad key: ' + key);
}
key = KeyMap[key].toString(16);
}
this.pendingScript.push('key --clearmodifiers ' + this.modString() + key);
this.callback();
};
AutoTypeEmitter.prototype.copyPaste = function(text) {
this.pendingScript.push('sleep 0.5');
Launcher.setClipboardText(text);
this.pendingScript.push('key --clearmodifiers shift+Insert');
this.pendingScript.push('sleep 0.5');
this.waitComplete();
};
AutoTypeEmitter.prototype.wait = function(time) {
this.pendingScript.push('sleep ' + (time / 1000));
this.callback();
};
AutoTypeEmitter.prototype.waitComplete = function(callback) {
if (this.pendingScript.length) {
const script = this.pendingScript.join(' ');
this.pendingScript.length = 0;
this.runScript(script, callback);
} else {
this.callback();
}
};
AutoTypeEmitter.prototype.modString = function() {
let mod = '';
Object.keys(this.mod).forEach(key => {
mod += key + '+';
});
return mod;
};
AutoTypeEmitter.prototype.runScript = function(script, callback) {
Launcher.spawn({
cmd: 'xdotool',
args: ['-'],
data: script,
complete: (err, stdout, code) => {
if (err && err.code === 'ENOENT') {
err = Locale.autoTypeErrorNotInstalled.replace('{}', 'xdotool');
}
const cb = callback || this.callback;
cb(err, stdout, code);
}
});
};
module.exports = AutoTypeEmitter;
@@ -1,93 +0,0 @@
const Launcher = require('../../comp/launcher');
const AutoTypeNativeHelper = require('../helper/auto-type-native-helper');
// https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
const KeyMap = {
tab: 0x09, enter: 0x0D, space: 0x20,
up: 0x26, down: 0x28, left: 0x25, right: 0x27, home: 0x24, end: 0x23, pgup: 0x21, pgdn: 0x22,
ins: 0x2D, del: 0x2E, bs: 0x08, esc: 0x1B,
win: 0x5B, rwin: 0x5C,
f1: 0x70, f2: 0x71, f3: 0x72, f4: 0x73, f5: 0x74, f6: 0x75, f7: 0x76, f8: 0x77, f9: 0x78,
f10: 0x79, f11: 0x7A, f12: 0x7B, f13: 0x7C, f14: 0x7D, f15: 0x7E, f16: 0x7F,
add: 0x6B, subtract: 0x6D, multiply: 0x6A, divide: 0x6F,
n0: 0x30, n1: 0x31, n2: 0x32, n3: 0x33, n4: 0x34,
n5: 0x35, n6: 0x36, n7: 0x37, n8: 0x38, n9: 0x39
};
const ModMap = {
'^': '^',
'+': '+',
'%': '%',
'^^': '^'
};
const AutoTypeEmitter = function(callback) {
this.callback = callback;
this.mod = {};
this.pendingScript = [];
};
AutoTypeEmitter.prototype.setMod = function(mod, enabled) {
if (enabled) {
this.mod[ModMap[mod]] = true;
} else {
delete this.mod[ModMap[mod]];
}
};
AutoTypeEmitter.prototype.text = function(text) {
if (text) {
this.pendingScript.push('text ' + this.modStr() + ' ' + text);
}
this.callback();
};
AutoTypeEmitter.prototype.key = function(key) {
if (typeof key !== 'number') {
if (!KeyMap[key]) {
return this.callback('Bad key: ' + key);
}
key = KeyMap[key];
}
this.pendingScript.push('key ' + this.modStr() + key);
this.callback();
};
AutoTypeEmitter.prototype.copyPaste = function(text) {
this.pendingScript.push('copypaste ' + text);
this.callback();
};
AutoTypeEmitter.prototype.wait = function(time) {
this.pendingScript.push('wait ' + time);
this.callback();
};
AutoTypeEmitter.prototype.waitComplete = function() {
if (this.pendingScript.length) {
const script = this.pendingScript.join('\n');
this.pendingScript.length = 0;
this.runScript(script);
} else {
this.callback();
}
};
AutoTypeEmitter.prototype.setDelay = function(delay) {
this.delay = delay || 0;
this.callback('Not implemented');
};
AutoTypeEmitter.prototype.modStr = function() {
return Object.keys(this.mod).join('');
};
AutoTypeEmitter.prototype.runScript = function(script) {
Launcher.spawn({
cmd: AutoTypeNativeHelper.getHelperPath(),
data: script,
complete: this.callback
});
};
module.exports = AutoTypeEmitter;
@@ -1,59 +0,0 @@
const Launcher = require('../../comp/launcher');
const ForeMostAppScript = 'tell application "System Events" to set frontApp to name of first process whose frontmost is true';
const ChromeScript = 'tell application "{}" to set appUrl to URL of active tab of front window\n' +
'tell application "{}" to set appTitle to title of active tab of front window\n' +
'return appUrl & "\n" & appTitle';
const SafariScript = 'tell application "{}" to set appUrl to URL of front document\n' +
'tell application "{}" to set appTitle to name of front document\n' +
'return appUrl & "\n" & appTitle';
const OtherAppsScript = 'tell application "System Events"\n' +
' tell process "{}"\n' +
' tell (1st window whose value of attribute "AXMain" is true)\n' +
' set windowTitle to value of attribute "AXTitle"\n' +
' end tell\n' +
' end tell\n' +
'end tell';
const AutoTypeHelper = function() {
};
AutoTypeHelper.prototype.getActiveWindowTitle = function(callback) {
AutoTypeHelper.exec(ForeMostAppScript, (err, out) => {
if (err) { return callback(err); }
const appName = out.trim();
// getting urls and titles from Chrome or Safari:
// - will suit in 90% cases
// - does not require assistive access
// - allows to get url
if (['Google Chrome', 'Chromium', 'Google Chrome Canary'].indexOf(appName) >= 0) {
AutoTypeHelper.exec(ChromeScript.replace(/\{}/g, appName), (err, out) => {
if (err) { return callback(err); }
const parts = out.split('\n');
return callback(null, (parts[1] || '').trim(), parts[0].trim());
});
} else if (['Safari', 'Webkit'].indexOf(appName) >= 0) {
AutoTypeHelper.exec(SafariScript.replace(/\{}/g, appName), (err, out) => {
if (err) { return callback(err); }
const parts = out.split('\n');
return callback(null, (parts[1] || '').trim(), parts[0].trim());
});
} else {
// special cases are not available. this method may ask the user about assistive access
AutoTypeHelper.exec(OtherAppsScript.replace(/\{}/g, appName), (err, out) => {
if (err) { return callback(err); }
return callback(null, out.trim());
});
}
});
};
AutoTypeHelper.exec = function(script, callback) {
Launcher.spawn({
cmd: 'osascript',
args: ['-e', script],
complete: callback
});
};
module.exports = AutoTypeHelper;
@@ -1,16 +0,0 @@
const Launcher = require('../../comp/launcher');
const AutoTypeHelper = function() {
};
AutoTypeHelper.prototype.getActiveWindowTitle = function(callback) {
Launcher.spawn({
cmd: 'xdotool',
args: ['getactivewindow', 'getwindowname'],
complete: function(err, res) {
return callback(err, res ? res.trim() : undefined);
}
});
};
module.exports = AutoTypeHelper;
@@ -1,20 +0,0 @@
const Launcher = require('../../comp/launcher');
const AutoTypeNativeHelper = require('./auto-type-native-helper');
const AutoTypeHelper = function() {
};
AutoTypeHelper.prototype.getActiveWindowTitle = function(callback) {
Launcher.spawn({
cmd: AutoTypeNativeHelper.getHelperPath(),
args: ['--window-info'],
complete: function(err, out) {
if (err) { return callback(err); }
const parts = out.split('\n');
return callback(null, (parts[0] || '').trim(),
parts[1] ? parts[1].trim() : undefined);
}
});
};
module.exports = AutoTypeHelper;
@@ -1,21 +0,0 @@
const Launcher = require('../../comp/launcher');
const Logger = require('../../util/logger');
const logger = new Logger('auto-type');
const AutoTypeNativeHelper = {
getHelperPath() {
if (this._helperPath) {
return this._helperPath;
}
const ext = process.platform === 'win32' ? '.exe' : '';
const helperRelPath = `helper/${process.platform}/KeeWebHelper${ext}`;
const helperPath = Launcher.getAppPath(helperRelPath);
Launcher.ensureRunnable(helperPath);
logger.debug('Using auto-type helper', helperPath);
this._helperPath = helperPath;
return helperPath;
}
};
module.exports = AutoTypeNativeHelper;
+165 -106
View File
@@ -1,44 +1,47 @@
const Backbone = require('backbone');
const AutoTypeParser = require('./auto-type-parser');
const AutoTypeFilter = require('./auto-type-filter');
const AutoTypeHelperFactory = require('./auto-type-helper-factory');
const Launcher = require('../comp/launcher');
const Alerts = require('../comp/alerts');
const AutoTypeSelectView = require('../views/auto-type/auto-type-select-view');
const Logger = require('../util/logger');
const Locale = require('../util/locale');
const Timeouts = require('../const/timeouts');
const AppSettingsModel = require('../models/app-settings-model');
const AutoTypeSequenceType = require('../const/autotype-sequencetype');
import { Events } from 'framework/events';
import { AutoTypeHelper } from 'auto-type/auto-type-helper';
import { AutoTypeParser } from 'auto-type/auto-type-parser';
import { SelectEntryFilter } from 'comp/app/select-entry-filter';
import { Launcher } from 'comp/launcher';
import { Features } from 'util/features';
import { Alerts } from 'comp/ui/alerts';
import { Timeouts } from 'const/timeouts';
import { AppSettingsModel } from 'models/app-settings-model';
import { AppModel } from 'models/app-model';
import { Locale } from 'util/locale';
import { Logger } from 'util/logger';
import { Links } from 'const/links';
import { SelectEntryView } from 'views/select/select-entry-view';
const logger = new Logger('auto-type');
const clearTextAutoTypeLog = localStorage.autoTypeDebug;
const clearTextAutoTypeLog = !!localStorage.debugAutoType;
const AutoType = {
helper: AutoTypeHelperFactory.create(),
enabled: !!(Launcher && Launcher.autoTypeSupported),
supportsEventsWithWindowId: !!(Launcher && Launcher.platform() === 'linux'),
selectEntryView: false,
pendingEvent: null,
running: false,
init(appModel) {
init() {
if (!this.enabled) {
return;
}
this.appModel = appModel;
Backbone.on('auto-type', this.handleEvent, this);
Backbone.on('main-window-blur main-window-will-close', this.resetPendingEvent, this);
Events.on('auto-type', (e) => this.handleEvent(e));
},
handleEvent(e) {
const entry = e && e.entry || null;
logger.debug('Auto type event', entry);
const entry = (e && e.entry) || null;
const sequence = (e && e.sequence) || null;
const context = (e && e.context) || null;
logger.info('Auto type event', entry);
if (this.running) {
logger.debug('Already running, skipping event');
logger.info('Already running, skipping event');
return;
}
if (entry) {
this.hideWindow(() => { this.runAndHandleResult({ entry }); });
this.hideWindow(() => {
this.runAndHandleResult({ entry, sequence, context });
});
} else {
if (this.selectEntryView) {
return;
@@ -54,44 +57,45 @@ const AutoType = {
}
},
runAndHandleResult(result) {
this.run(result, err => {
runAndHandleResult(result, windowId) {
this.run(result, windowId, (err) => {
if (err) {
let body = Locale.autoTypeErrorGeneric.replace('{}', err.message || err.toString());
let link;
if (err.keyPressFailed && Features.isMac) {
body = Locale.autoTypeErrorAccessibilityMacOS;
link = Links.AutoTypeMacOS;
}
Alerts.error({
header: Locale.autoTypeError,
body: Locale.autoTypeErrorGeneric.replace('{}', err.toString())
body,
link
});
}
});
if (AppSettingsModel.instance.get('lockOnAutoType')) {
Backbone.trigger('lock-workspace');
if (AppSettingsModel.lockOnAutoType) {
Events.emit('lock-workspace');
}
},
run(result, callback) {
run(result, windowId, callback) {
this.running = true;
let sequence;
if (result.sequenceType === AutoTypeSequenceType.PASSWORD) {
sequence = '{PASSWORD}';
} else if (result.sequenceType === AutoTypeSequenceType.USERNAME) {
sequence = '{USERNAME}';
} else {
sequence = result.entry.getEffectiveAutoTypeSeq();
}
logger.debug('Start', sequence);
const sequence = result.sequence || result.entry.getEffectiveAutoTypeSeq();
const context = result.context;
logger.info('Start', sequence);
const ts = logger.ts();
try {
const parser = new AutoTypeParser(sequence);
const runner = parser.parse();
logger.debug('Parsed', this.printOps(runner.ops));
runner.resolve(result.entry, err => {
logger.info('Parsed', this.printOps(runner.ops));
runner.resolve(result.entry, context, (err) => {
if (err) {
this.running = false;
logger.error('Resolve error', err);
return callback && callback(err);
}
logger.debug('Resolved', this.printOps(runner.ops));
logger.info('Resolved', this.printOps(runner.ops));
if (result.entry.autoTypeObfuscation) {
try {
runner.obfuscate();
@@ -100,17 +104,17 @@ const AutoType = {
logger.error('Obfuscate error', e);
return callback && callback(e);
}
logger.debug('Obfuscated');
logger.info('Obfuscated');
}
runner.run(err => {
runner.run((err) => {
this.running = false;
if (err) {
logger.error('Run error', err);
return callback && callback(err);
}
logger.debug('Complete', logger.ts(ts));
logger.info('Complete', logger.ts(ts));
return callback && callback();
});
}, windowId);
});
} catch (ex) {
this.running = false;
@@ -123,7 +127,7 @@ const AutoType = {
try {
const parser = new AutoTypeParser(sequence);
const runner = parser.parse();
runner.resolve(entry, callback);
runner.resolve(entry, null, callback);
} catch (ex) {
return callback(ex);
}
@@ -149,7 +153,7 @@ const AutoType = {
},
hideWindow(callback) {
logger.debug('Hide window');
logger.info('Hide window');
if (Launcher.isAppFocused()) {
Launcher.hideApp();
setTimeout(callback, Timeouts.AutoTypeAfterHide);
@@ -158,97 +162,152 @@ const AutoType = {
}
},
getActiveWindowTitle(callback) {
logger.debug('Get window title');
return this.helper.getActiveWindowTitle((err, title, url) => {
getActiveWindowInfo(callback) {
logger.info('Getting window info');
const helper = new AutoTypeHelper();
return helper.getActiveWindowInfo((err, windowInfo) => {
if (err) {
logger.error('Error get window title', err);
logger.error('Error getting window info', err);
} else {
if (!url) {
if (!windowInfo.url) {
// try to find a URL in the title
const urlMatcher = new RegExp(
'https?:\\/\\/(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{2,256}\\.[a-z]{2,4}\\b([-a-zA-Z0-9@:%_\\+.~#?&//=]*)'
);
const urlMatches = urlMatcher.exec(title);
url = urlMatches && urlMatches.length > 0 ? urlMatches[0] : null;
const urlMatcher =
/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\\+~#=]{2,256}\.[a-z]{2,4}\b([-a-zA-Z0-9@:%_\\+.~#?&\/=]*)/;
const urlMatches = urlMatcher.exec(windowInfo.title);
windowInfo.url = urlMatches && urlMatches.length > 0 ? urlMatches[0] : null;
}
logger.debug('Window title', title, url);
logger.info('Window info', windowInfo.id, windowInfo.title, windowInfo.url);
}
return callback(err, title, url);
return callback(err, windowInfo);
});
},
activeWindowMatches(windowInfo, callback) {
if (!windowInfo || !windowInfo.id) {
logger.info('Skipped active window check because window id is unknown');
return callback(true);
}
this.getActiveWindowInfo((err, activeWindowInfo) => {
if (!activeWindowInfo) {
logger.info('Error during active window check, something is wrong', err);
return callback(false);
}
if (activeWindowInfo.id !== windowInfo.id && !this.supportsEventsWithWindowId) {
logger.info(
`Active window doesn't match: ID is different. ` +
`Expected ${windowInfo.id}, got ${activeWindowInfo.id}`
);
return callback(false, activeWindowInfo);
}
if (activeWindowInfo.url !== windowInfo.url && !this.supportsEventsWithWindowId) {
logger.info(
`Active window doesn't match: url is different. ` +
`Expected "${windowInfo.url}", got "${activeWindowInfo.url}"`
);
return callback(false, activeWindowInfo);
}
logger.info('Active window matches');
callback(true, activeWindowInfo);
});
},
selectEntryAndRun() {
this.getActiveWindowTitle((e, title, url) => {
const filter = new AutoTypeFilter({title, url}, this.appModel);
const evt = { filter };
if (!this.appModel.files.hasOpenFiles()) {
this.pendingEvent = evt;
this.appModel.files.once('update', this.processPendingEvent, this);
logger.debug('auto-type event delayed');
this.getActiveWindowInfo(async (e, windowInfo) => {
const filter = new SelectEntryFilter(
windowInfo,
AppModel.instance,
AppModel.instance.files,
{
autoType: true
}
);
const evt = { filter, windowInfo };
if (!AppModel.instance.files.hasOpenFiles()) {
logger.info('auto-type event delayed');
this.focusMainWindow();
} else {
this.processEventWithFilter(evt);
try {
await AppModel.instance.unlockAnyFile('autoTypeUnlockMessage');
} catch {
logger.info('auto-type event canceled');
return;
}
if (this.selectEntryView) {
this.selectEntryView.show();
}
}
logger.info('processing auto-type event');
this.processEventWithFilter(evt);
});
},
focusMainWindow() {
setTimeout(() => Launcher.showMainWindow(), Timeouts.RedrawInactiveWindow);
if (!Launcher.isAppFocused()) {
setTimeout(() => Launcher.showMainWindow(), Timeouts.RedrawInactiveWindow);
}
},
processEventWithFilter(evt) {
const entries = evt.filter.getEntries();
if (entries.length === 1 && AppSettingsModel.instance.get('directAutotype')) {
let entries = evt.filter.getEntries();
if (entries.length === 1 && AppSettingsModel.directAutotype) {
this.hideWindow(() => {
this.runAndHandleResult({ entry: entries.at(0) });
this.runAndHandleResult({ entry: entries[0] }, evt.windowInfo.id);
});
return;
}
this.focusMainWindow();
evt.filter.ignoreWindowInfo = true;
this.selectEntryView = new AutoTypeSelectView({
model: { filter: evt.filter }
}).render();
this.selectEntryView.on('result', result => {
logger.debug('Entry selected', result);
if (entries.length === 0) {
if (evt.filter.useUrl) {
evt.filter.useUrl = false;
if (evt.filter.title && AppSettingsModel.autoTypeTitleFilterEnabled) {
evt.filter.useTitle = true;
}
}
entries = evt.filter.getEntries();
if (entries.length === 0 && evt.filter.useTitle) {
evt.filter.useTitle = false;
}
}
const humanReadableTarget = evt.filter.title || evt.filter.url;
const topMessage = humanReadableTarget
? Locale.autoTypeMsgMatchedByWindow.replace('{}', humanReadableTarget)
: Locale.autoTypeMsgNoWindow;
this.selectEntryView = new SelectEntryView({
isAutoType: true,
itemOptions: true,
filter: evt.filter,
topMessage
});
this.selectEntryView.on('result', (result) => {
logger.info('Entry selected', result);
this.selectEntryView.off('result');
this.selectEntryView.remove();
this.selectEntryView = null;
this.hideWindow(() => {
if (result) {
this.runAndHandleResult(result);
if (result?.entry) {
this.activeWindowMatches(evt.windowInfo, (matches, activeWindowInfo) => {
if (matches) {
this.runAndHandleResult(result, evt.windowInfo.id);
}
});
}
});
});
this.selectEntryView.on('show-open-files', () => {
this.selectEntryView.render();
this.selectEntryView.on('show-open-files', async () => {
this.selectEntryView.hide();
Backbone.trigger('open-file');
Backbone.once('closed-open-view', () => {
this.selectEntryView.show();
this.selectEntryView.setupKeys();
}, this);
try {
await AppModel.instance.unlockAnyFile('autoTypeUnlockMessage');
} catch {
this.selectEntryView.emit('result', undefined);
return;
}
this.selectEntryView.show();
this.selectEntryView.render();
});
},
resetPendingEvent() {
if (this.pendingEvent) {
this.pendingEvent = null;
this.appModel.files.off('update', this.processPendingEvent, this);
logger.debug('auto-type event cancelled');
}
},
processPendingEvent() {
if (!this.pendingEvent) {
return;
}
logger.debug('processing pending auto-type event');
const evt = this.pendingEvent;
this.appModel.files.off('update', this.processPendingEvent, this);
this.pendingEvent = null;
this.processEventWithFilter(evt);
}
};
module.exports = AutoType;
export { AutoType };
+188
View File
@@ -0,0 +1,188 @@
import 'util/kdbxweb/protected-value';
import { h, render } from 'preact';
import { App } from 'ui/app';
import { Events } from 'util/events';
import { StartProfiler } from 'util/logging/start-profiler';
import { AppRightsChecker } from 'comp/launcher/app-rights-checker';
import { ExportApi } from 'comp/app/export-api';
import { SingleInstanceChecker } from 'comp/browser/single-instance-checker';
import { FocusDetector } from 'comp/browser/focus-detector';
import { IdleTracker } from 'comp/browser/idle-tracker';
import { ThemeWatcher } from 'comp/browser/theme-watcher';
import { KeyHandler } from 'comp/browser/key-handler';
import { PopupNotifier } from 'comp/browser/popup-notifier';
import { SettingsManager } from 'comp/settings/settings-manager';
import { Alerts } from 'comp/ui/alerts';
import { AppSettings } from 'models/app-settings';
import { RuntimeData } from 'models/runtime-data';
import { Features } from 'util/features';
import { KdbxwebInit } from 'comp/kdbxweb/kdbxweb-init';
import { Locale } from 'util/locale';
import { Logger } from 'util/logger';
import { FeatureTester } from 'util/browser/feature-tester';
import { UsbListener } from 'comp/devices/usb-listener';
import { noop } from 'util/fn';
import { ConfigLoader } from 'comp/settings/config-loader';
import { WindowClass } from 'comp/browser/window-class';
import { FileManager } from 'models/file-manager';
import { Updater } from './comp/app/updater';
import { Timeouts } from 'const/timeouts';
import { PluginManager } from 'plugins/plugin-manager';
import { Workspace } from 'models/workspace';
declare global {
interface Window {
kw: typeof ExportApi;
}
}
StartProfiler.milestone('loading modules');
document.addEventListener('DOMContentLoaded', () => {
bootstrap().catch(noop);
});
export async function bootstrap(): Promise<void> {
StartProfiler.milestone('document ready');
const logger = new Logger('bootstrap');
try {
await loadConfigs();
await initModules();
await loadRemoteConfig();
await ensureCanRun();
addWindowClasses();
initUsbListener();
await showApp();
postInit();
} catch (e) {
logger.error('Error starting app', e);
}
async function ensureCanRun() {
if (Features.isFrame && !AppSettings.allowIframes) {
return Promise.reject(
'Running in iframe is not allowed (this can be changed in the app config).'
);
}
try {
await FeatureTester.test();
StartProfiler.milestone('checking features');
} catch (e) {
Alerts.error({
header: Locale.appSettingsError,
body: Locale.appNotSupportedError,
pre: String(e),
buttons: [],
esc: undefined,
enter: undefined,
click: undefined
});
logger.error('Feature test failed', e);
throw new Error(`Feature test failed`);
}
}
function loadConfigs() {
return Promise.all([AppSettings.init(), RuntimeData.init(), FileManager.init()]).then(
() => {
StartProfiler.milestone('loading configs');
}
);
}
async function initModules() {
KeyHandler.init();
PopupNotifier.init();
KdbxwebInit.init();
FocusDetector.init();
// AutoType.init(); // TODO
ThemeWatcher.init();
SettingsManager.init();
await PluginManager.init();
window.kw = ExportApi;
StartProfiler.milestone('initializing modules');
}
async function loadRemoteConfig() {
SettingsManager.setBySettings();
const loaded = await ConfigLoader.loadConfig();
if (loaded) {
SettingsManager.setBySettings();
}
StartProfiler.milestone('loading remote config');
}
function addWindowClasses() {
WindowClass.init();
StartProfiler.milestone('adding window classes');
}
function initUsbListener() {
UsbListener.init();
StartProfiler.milestone('starting usb');
}
function showApp() {
return Promise.resolve().then(() => {
const skipHttpsWarning = AppSettings.skipHttpsWarning;
const protocolIsInsecure = ['https:', 'file:', 'app:'].indexOf(location.protocol) < 0;
const hostIsInsecure = location.hostname !== 'localhost';
if (protocolIsInsecure && hostIsInsecure && !skipHttpsWarning) {
return new Promise<void>((resolve) => {
Alerts.error({
header: Locale.appSecWarn,
icon: 'user-secret',
esc: undefined,
enter: undefined,
click: undefined,
body: Locale.appSecWarnBody1 + '\n\n' + Locale.appSecWarnBody2,
buttons: [{ result: '', title: Locale.appSecWarnBtn, error: true }],
complete: () => {
resolve(showView());
}
});
});
} else {
return showView().then(
() => new Promise<void>((resolve) => requestAnimationFrame(() => resolve()))
);
}
});
}
function postInit() {
Updater.init();
SingleInstanceChecker.init();
AppRightsChecker.init().catch(noop);
IdleTracker.init();
// BrowserExtensionConnector.init(appModel); // TODO
setTimeout(() => {
PluginManager.runAutoUpdate().catch(noop);
}, Timeouts.PluginsAutoUpdateAfterStart);
}
function showView() {
Workspace.showOpen();
const root = document.querySelector('.app');
if (root) {
const app = h(App, null);
render(app, document.body, root);
}
StartProfiler.milestone('first view rendering');
Events.emit('app-ready');
StartProfiler.milestone('app ready event');
StartProfiler.report();
return Promise.resolve();
}
}
@@ -1,51 +0,0 @@
const Backbone = require('backbone');
const EntryModel = require('../models/entry-model');
const Comparators = require('../util/comparators');
const EntryCollection = Backbone.Collection.extend({
model: EntryModel,
comparator: null,
comparators: {
'none': null,
'title': Comparators.stringComparator('title', true),
'-title': Comparators.stringComparator('title', false),
'website': Comparators.stringComparator('url', true),
'-website': Comparators.stringComparator('url', false),
'user': Comparators.stringComparator('user', true),
'-user': Comparators.stringComparator('user', false),
'created': Comparators.dateComparator('created', true),
'-created': Comparators.dateComparator('created', false),
'updated': Comparators.dateComparator('updated', true),
'-updated': Comparators.dateComparator('updated', false),
'-attachments': function(x, y) { return this.attachmentSortVal(x).localeCompare(this.attachmentSortVal(y)); },
'-rank': Comparators.rankComparator()
},
defaultComparator: 'title',
filter: null,
initialize: function(models, options) {
const comparatorName = options && options.comparator || this.defaultComparator;
this.comparator = this.comparators[comparatorName];
},
sortEntries: function(comparator, filter) {
this.filter = filter;
this.comparator = this.comparators[comparator] || this.comparators[this.defaultComparator];
this.sort();
},
attachmentSortVal: function(entry) {
const att = entry.attachments;
let str = att.length ? String.fromCharCode(64 + att.length) : 'Z';
if (att[0]) {
str += att[0].title;
}
return str;
}
});
module.exports = EntryCollection;
@@ -1,24 +0,0 @@
const Backbone = require('backbone');
const FileModel = require('../models/file-model');
const FileCollection = Backbone.Collection.extend({
model: FileModel,
hasOpenFiles: function() {
return this.some(file => file.get('open'));
},
hasUnsavedFiles: function() {
return this.some(file => file.get('modified'));
},
hasDirtyFiles: function() {
return this.some(file => file.get('dirty'));
},
getByName: function(name) {
return this.find(file => file.get('name').toLowerCase() === name.toLowerCase());
}
});
module.exports = FileCollection;
@@ -1,42 +0,0 @@
const Backbone = require('backbone');
const FileInfoModel = require('../models/file-info-model');
const SettingsStore = require('../comp/settings-store');
const FileInfoCollection = Backbone.Collection.extend({
model: FileInfoModel,
initialize: function () {
},
load: function () {
return SettingsStore.load('file-info').then(data => {
if (data) {
this.reset(data, {silent: true});
}
});
},
save: function () {
SettingsStore.save('file-info', this.toJSON());
},
getLast: function () {
return this.first();
},
getMatch: function (storage, name, path) {
return this.find(fi => {
return (fi.get('storage') || '') === (storage || '') &&
(fi.get('name') || '') === (name || '') &&
(fi.get('path') || '') === (path || '');
});
},
getByName: function(name) {
return this.find(file => file.get('name').toLowerCase() === name.toLowerCase());
}
});
FileInfoCollection.instance = new FileInfoCollection();
module.exports = FileInfoCollection;
@@ -1,8 +0,0 @@
const Backbone = require('backbone');
const GroupModel = require('../models/group-model');
const GroupCollection = Backbone.Collection.extend({
model: GroupModel
});
module.exports = GroupCollection;
@@ -1,8 +0,0 @@
const Backbone = require('backbone');
const MenuItemModel = require('../../models/menu/menu-item-model');
const MenuItemCollection = Backbone.Collection.extend({
model: MenuItemModel
});
module.exports = MenuItemCollection;
@@ -1,8 +0,0 @@
const Backbone = require('backbone');
const MenuOptionModel = require('../../models/menu/menu-option-model');
const MenuOptionCollection = Backbone.Collection.extend({
model: MenuOptionModel
});
module.exports = MenuOptionCollection;
@@ -1,8 +0,0 @@
const Backbone = require('backbone');
const MenuSectionModel = require('../../models/menu/menu-section-model');
const MenuSectionCollection = Backbone.Collection.extend({
model: MenuSectionModel
});
module.exports = MenuSectionCollection;
-85
View File
@@ -1,85 +0,0 @@
const ModalView = require('../views/modal-view');
const Locale = require('../util/locale');
const Alerts = {
alertDisplayed: false,
buttons: {
ok: {result: 'yes', get title() { return Locale.alertOk; }},
yes: {result: 'yes', get title() { return Locale.alertYes; }},
no: {result: '', get title() { return Locale.alertNo; }},
cancel: {result: '', get title() { return Locale.alertCancel; }}
},
alert: function(config) {
if (config.skipIfAlertDisplayed && Alerts.alertDisplayed) {
return null;
}
Alerts.alertDisplayed = true;
const view = new ModalView({ model: config });
view.render();
view.on('result', (res, check) => {
Alerts.alertDisplayed = false;
if (res && config.success) {
config.success(res, check);
}
if (!res && config.cancel) {
config.cancel();
}
if (config.complete) {
config.complete(res, check);
}
});
return view;
},
notImplemented: function() {
this.alert({
header: Locale.notImplemented,
body: '',
icon: 'exclamation-triangle',
buttons: [this.buttons.ok],
esc: '',
click: '',
enter: ''
});
},
info: function(config) {
this.alert(_.extend({
header: '',
body: '',
icon: 'info',
buttons: [this.buttons.ok],
esc: '',
click: '',
enter: ''
}, config));
},
error: function(config) {
this.alert(_.extend({
header: '',
body: '',
icon: 'exclamation-circle',
buttons: [this.buttons.ok],
esc: '',
click: '',
enter: ''
}, config));
},
yesno: function(config) {
this.alert(_.extend({
header: '',
body: '',
icon: 'question',
buttons: [this.buttons.yes, this.buttons.no],
esc: '',
click: '',
enter: 'yes'
}, config));
}
};
module.exports = Alerts;
-77
View File
@@ -1,77 +0,0 @@
const FeatureDetector = require('../util/feature-detector');
const Alerts = require('../comp/alerts');
const AppSettingsModel = require('../models/app-settings-model');
const Launcher = require('./launcher');
const Locale = require('../util/locale');
const AppRightsChecker = {
AppPath: '/Applications/KeeWeb.app',
init() {
if (!FeatureDetector.isDesktop || !FeatureDetector.isMac) {
return;
}
if (AppSettingsModel.instance.get('skipFolderRightsWarning')) {
return;
}
if (!Launcher.getAppPath().startsWith(this.AppPath)) {
return;
}
this.needRunInstaller(needRun => {
if (needRun) {
this.showAlert();
this.runInstaller();
}
});
},
needRunInstaller(callback) {
Launcher.statFile(this.AppPath, stat => {
const folderIsRoot = stat && stat.uid === 0;
callback(!folderIsRoot);
});
},
showAlert() {
const command = 'sudo chown -R root ' + this.AppPath;
this.alert = Alerts.alert({
icon: 'lock',
header: Locale.appRightsAlert,
body: Locale.appRightsAlertBody1.replace('{}', `<code>${this.AppPath}</code>`) +
'<br/>' + Locale.appRightsAlertBody2 + `: <pre>${command}</pre>`,
buttons: [
{result: 'skip', title: Locale.alertDoNotAsk, error: true},
Alerts.buttons.ok
],
success: (result) => {
if (result === 'skip') {
this.dontAskAnymore();
}
this.alert = null;
}
});
},
runInstaller() {
Launcher.spawn({
cmd: this.AppPath + '/Contents/Installer/KeeWeb\ Installer.app/Contents/MacOS/applet',
complete: () => {
this.needRunInstaller(needRun => {
if (this.alert && !needRun) {
this.alert.closeWithResult('cancel');
}
});
}
});
},
dontAskAnymore() {
this.needRunInstaller(needRun => {
if (needRun) {
AppSettingsModel.instance.set('skipFolderRightsWarning', true);
}
});
}
};
module.exports = AppRightsChecker;
+5
View File
@@ -0,0 +1,5 @@
const DragDropInfo = {
dragObject: null as unknown
};
export { DragDropInfo };
+29
View File
@@ -0,0 +1,29 @@
import { AppSettingsFieldName, AppSettings } from 'models/app-settings';
import { RuntimeData } from 'models/runtime-data';
const ExportApi = {
settings: {
get(key?: AppSettingsFieldName): unknown {
return key ? AppSettings[key] : { ...AppSettings };
},
set(key: AppSettingsFieldName, value: unknown): boolean {
return AppSettings.set(key, value);
},
del(key: AppSettingsFieldName): void {
AppSettings.delete(key);
}
},
runtimeData: {
get(key?: string): unknown {
return key ? RuntimeData.get(key) : { ...RuntimeData };
},
set(key: string, value: unknown): boolean {
return RuntimeData.set(key, value);
},
del(key: string): void {
RuntimeData.delete(key);
}
}
};
export { ExportApi };
+689
View File
@@ -0,0 +1,689 @@
import * as kdbxweb from 'kdbxweb';
import { Logger } from 'util/logger';
import { Storage } from 'storage';
import { Locale } from 'util/locale';
import { IdGenerator } from 'util/generators/id-generator';
import { OpenParams } from 'models/ui/open-state';
import { FileManager } from 'models/file-manager';
import { File } from 'models/file';
import { FileInfo } from 'models/file-info';
import {
StorageFileData,
StorageFileNotFoundError,
StorageFileOptions,
StorageFileStat,
StorageRevConflictError,
StorageSaveResult
} from 'storage/types';
import { AppSettings } from 'models/app-settings';
import { errorToString, noop } from 'util/fn';
import { StorageBase } from 'storage/storage-base';
import { UrlFormat } from 'util/formatting/url-format';
import { DateFormat } from 'util/formatting/date-format';
const MaxLoadLoops = 3;
interface FileSyncOptions {
storage?: string;
path?: string;
opts: StorageFileOptions;
}
interface SyncContext {
logger: Logger;
file: File;
fileInfo: FileInfo;
storage: StorageBase;
path: string;
stat?: StorageFileStat;
opts?: StorageFileOptions;
retryCount: number;
}
class FileController {
async open(params: OpenParams): Promise<File> {
const logger = new Logger('open', params.name);
logger.info('File open request');
if (!params.name) {
throw new Error('Empty name');
}
const fileInfo = params.id
? FileManager.getFileInfoById(params.id)
: FileManager.getFileInfo(params.name, params.storage, params.path);
if (!params.opts && fileInfo && fileInfo.opts) {
params.opts = fileInfo.opts;
}
if (fileInfo && fileInfo.modified) {
logger.info('Open file from cache because it is modified');
const file = await this.openFileFromCache(params, fileInfo, logger);
logger.info('Sync just opened modified file');
setTimeout(() => {
this.syncFile(file).catch(noop);
}, 0);
return file;
} else if (params.fileData) {
logger.info('Open file from supplied content');
if (params.storage === 'file' && params.path) {
const stat = await Storage.file.stat(params.path);
params.rev = stat.rev;
return this.openFileWithData(params, fileInfo, params.fileData, false);
} else {
return this.openFileWithData(params, fileInfo, params.fileData, true);
}
} else if (!params.storage && fileInfo) {
logger.info('Open file from cache as main storage');
return this.openFileFromCache(params, fileInfo, logger);
} else if (
fileInfo?.openDate &&
fileInfo.rev === params.rev &&
fileInfo.storage !== 'file' &&
!AppSettings.disableOfflineStorage
) {
logger.info('Open file from cache because it is latest');
try {
return this.openFileFromCache(params, fileInfo, logger);
} catch (err) {
if (err instanceof kdbxweb.KdbxError) {
// TODO: || err.ykError
throw err;
}
logger.info('Error loading file from cache, trying to open from storage', err);
return this.openFileFromStorage(params, fileInfo, logger, true);
}
} else if (
!fileInfo ||
!fileInfo.openDate ||
params.storage === 'file' ||
AppSettings.disableOfflineStorage
) {
return this.openFileFromStorage(params, fileInfo, logger, false);
} else {
logger.info('Open file from cache, will sync after load', params.storage);
let file: File;
try {
file = await this.openFileFromCache(params, fileInfo, logger);
} catch (err) {
if (err instanceof kdbxweb.KdbxError) {
// TODO: || err.ykError
throw err;
}
logger.info('Error loading file from cache, trying to open from storage', err);
return this.openFileFromStorage(params, fileInfo, logger, true);
}
logger.info('Sync just opened file');
setTimeout(() => {
this.syncFile(file).catch(noop);
}, 0);
return file;
}
}
private async openFileFromCache(
params: OpenParams,
fileInfo: FileInfo,
logger: Logger
): Promise<File> {
let data: ArrayBuffer;
try {
const res = await Storage.cache.load(fileInfo.id);
if (!res?.data) {
throw new Error(Locale.openFileNoCacheError);
}
data = res.data;
logger.info('Loaded from cache');
} catch (err) {
logger.info('Loaded error from cache', err);
throw err;
}
return this.openFileWithData(params, fileInfo, data, false);
}
private async openFileFromStorage(
params: OpenParams,
fileInfo: FileInfo | undefined,
logger: Logger,
noCache: boolean
): Promise<File> {
if (!params.storage) {
throw new Error('Storage open error: empty storage');
}
if (!params.path) {
throw new Error('Storage open error: empty path');
}
logger.info('Open file from storage', params.storage);
const storage = Storage.get(params.storage ?? '');
if (!storage) {
logger.error('Storage not found', storage);
throw new Error(`Storage not found: ${storage ?? ''}`);
}
const cacheRev = (fileInfo && fileInfo.rev) || null;
if (cacheRev && storage.stat) {
logger.info('Stat file');
let stat: StorageFileStat;
try {
stat = await storage.stat(params.path, params.opts);
} catch (err) {
if (
!noCache &&
fileInfo &&
storage.name !== 'file' &&
!AppSettings.disableOfflineStorage
) {
logger.info('Open file from cache because of stat error', err);
return this.openFileFromCache(params, fileInfo, logger);
} else {
logger.info('Stat error', err);
throw err;
}
}
if (
!noCache &&
fileInfo &&
storage.name !== 'file' &&
stat.rev === cacheRev &&
!AppSettings.disableOfflineStorage
) {
logger.info('Open file from cache because it is latest');
return this.openFileFromCache(params, fileInfo, logger);
}
logger.info(`Open file from storage (${stat.rev ?? '(empty)'}, local ${cacheRev})`);
}
logger.info('Load from storage');
let res: StorageFileData;
try {
res = await storage.load(params.path, params.opts);
} catch (err) {
if (fileInfo && fileInfo.openDate && !AppSettings.disableOfflineStorage) {
logger.info('Open file from cache because of storage load error', err);
return this.openFileFromCache(params, fileInfo, logger);
} else {
logger.info('Storage load error', err);
throw err;
}
}
logger.info('Open file from content loaded from storage');
params.fileData = res.data;
params.rev = res.rev;
const needSaveToCache = storage.name !== 'file';
return this.openFileWithData(params, fileInfo, res.data, needSaveToCache);
}
private async openFileWithData(
params: OpenParams,
fileInfo: FileInfo | undefined,
data: ArrayBuffer,
updateCacheOnSuccess: boolean
): Promise<File> {
if (!params.name) {
throw new Error('Open file without name');
}
if (!params.password) {
throw new Error('Open file without password');
}
const logger = new Logger('open', params.name);
let needLoadKeyFile = false;
if (!params.keyFileData && fileInfo && fileInfo.keyFileName) {
params.keyFileName = fileInfo.keyFileName;
if (AppSettings.rememberKeyFiles === 'data' && fileInfo.keyFileHash) {
params.keyFileData = File.createKeyFileWithHash(fileInfo.keyFileHash);
} else if (AppSettings.rememberKeyFiles === 'path' && fileInfo.keyFilePath) {
params.keyFilePath = fileInfo.keyFilePath;
if (Storage.file.enabled) {
needLoadKeyFile = true;
}
}
} else if (params.keyFilePath && !params.keyFileData && !fileInfo) {
needLoadKeyFile = true;
}
if (needLoadKeyFile && params.keyFilePath) {
let data: ArrayBuffer;
try {
const res = await Storage.file.load(params.keyFilePath);
data = res.data;
} catch (err) {
logger.info('Storage load error', err);
throw err;
}
params.keyFileData = data;
}
const id = fileInfo ? fileInfo.id : IdGenerator.uuid();
if (FileManager.getFileById(id)) {
throw new Error('Duplicate file id');
}
const file = await File.open(id, params.name, params.password, data, params.keyFileData);
file.batchSet(() => {
file.storage = params.storage;
file.path = params.path;
file.keyFileName = params.keyFileName;
file.keyFilePath = params.keyFilePath;
file.backup = fileInfo?.backup;
file.chalResp = params.chalResp;
file.syncDate = fileInfo?.syncDate;
// if (params.encryptedPassword) { // TODO: touch id
// file.encryptedPassword = fileInfo?.encryptedPassword;
// file.encryptedPasswordDate = fileInfo?.encryptedPasswordDate || new Date();
// }
});
if (fileInfo?.modified) {
if (fileInfo.editState) {
logger.info('Loaded local edit state');
file.setLocalEditState(fileInfo.editState);
}
logger.info('Mark file as modified');
file.modified = true;
}
if (updateCacheOnSuccess && !AppSettings.disableOfflineStorage && params.fileData) {
logger.info('Save loaded file to cache');
await Storage.cache.save(file.id, params.fileData);
}
const rev = params.rev || (fileInfo && fileInfo.rev);
// this.setFileOpts(file, params.opts); // TODO: file opts
logger.info('Add last open file', file.id, file.name, file.storage, file.path, rev);
FileManager.addLastOpenFileInfo(file, rev);
FileManager.addFile(file);
// this.fileOpened(file, data, params); // TODO: fileOpened
return file;
}
async syncFile(file: File, options?: FileSyncOptions): Promise<void> {
if (file.demo) {
return;
}
const logger = new Logger('sync', file.name);
const storageName = options?.storage || file.storage;
const storage = storageName ? Storage.get(storageName) : undefined;
const opts = options?.opts || file.opts;
let path = options?.path || file.path;
if (storage?.getPathForName && (!path || storage.name !== file.storage)) {
path = storage.getPathForName(file.name);
}
const optionsForLogging = { ...options };
if (optionsForLogging.opts && optionsForLogging.opts.password) {
optionsForLogging.opts = { ...optionsForLogging.opts };
optionsForLogging.opts.password = '***';
}
logger.info('Sync started', storage, path, optionsForLogging);
const fileInfo = this.getOrCreateFileInfo(file, logger);
let syncError: unknown;
try {
if (file.syncing) {
throw new Error('Sync in progress');
}
file.setSyncProgress();
if (!storage) {
if (!file.modified && fileInfo.id === file.id) {
logger.info('Local, not modified');
} else {
logger.info('Local, save to cache');
const data = await file.getData();
try {
await Storage.cache.save(fileInfo.id, data);
logger.info('Saved to cache');
} catch (err) {
logger.info('Cache save error', err);
throw err;
}
// this.scheduleBackupFile(file, data); // TODO: backups
}
} else {
if (!path) {
throw new Error('Cannot sync file to storage but without path');
}
const ctx: SyncContext = {
logger,
file,
fileInfo,
storage,
path,
opts,
retryCount: 0
};
logger.info('Stat file');
let stat: StorageFileStat | undefined;
try {
stat = await storage.stat(path, opts);
ctx.stat = stat;
} catch (err) {
if (err instanceof StorageFileNotFoundError) {
logger.info('File does not exist in storage, creating');
await this.saveToCacheAndStorage(ctx);
} else if (file.dirty) {
if (AppSettings.disableOfflineStorage) {
logger.info('Stat error, dirty, cache is disabled', err);
throw err;
}
logger.info('Stat error, dirty, save to cache');
const data = await file.getData();
try {
await Storage.cache.save(fileInfo.id, data);
file.dirty = false;
logger.info('Saved to cache, exit with error', err);
} catch (e) {
logger.error('Error saving to cache', e);
}
throw err;
} else {
logger.info('Stat error, not dirty', err);
throw err;
}
}
if (stat) {
if (stat.rev === fileInfo.rev) {
if (file.modified) {
logger.info('Stat found same version, modified, saving');
await this.saveToCacheAndStorage(ctx);
} else {
logger.info('Stat found same version, not modified');
}
} else {
logger.info('Found new version, loading from storage');
await this.loadFromStorageAndMerge(ctx);
}
}
}
logger.info('Sync finished OK');
} catch (e) {
syncError = e;
logger.error('Sync finished with error', syncError);
}
file.setSyncComplete(path, storageName, syncError ? errorToString(syncError) : undefined);
fileInfo.batchSet(() => {
fileInfo.name = file.name;
fileInfo.storage = storageName;
fileInfo.path = path;
// fileInfo.opts = this.getStoreOpts(file); // TODO: storage opts
fileInfo.modified = file.dirty ? fileInfo.modified : file.modified;
fileInfo.editState = file.dirty ? fileInfo.editState : file.getLocalEditState();
fileInfo.syncDate = file.syncDate;
fileInfo.chalResp = file.chalResp;
if (AppSettings.rememberKeyFiles === 'data') {
fileInfo.keyFileName = file.keyFileName;
fileInfo.keyFileHash = file.getKeyFileHash();
}
});
if (!FileManager.getFileById(fileInfo.id)) {
FileManager.addFileInfo(fileInfo, true);
}
if (syncError) {
throw syncError;
}
}
private getOrCreateFileInfo(file: File, logger: Logger): FileInfo {
let fileInfo = FileManager.getFileInfoById(file.id);
if (!fileInfo) {
logger.info('Create new file info');
const dt = new Date();
fileInfo = new FileInfo({
id: file.id,
name: file.name,
storage: file.storage,
path: file.path,
// opts: this.getStoreOpts(file), // TODO: store opts
modified: file.modified,
syncDate: dt,
openDate: dt,
backup: file.backup
});
}
return fileInfo;
}
private async saveToStorage(ctx: SyncContext, data: ArrayBuffer) {
ctx.logger.info('Save data to storage');
const storageRev = ctx.fileInfo.storage === ctx.storage.name ? ctx.fileInfo.rev : undefined;
let saveResult: StorageSaveResult;
try {
saveResult = await ctx.storage.save(ctx.path, data, ctx.opts, storageRev);
} catch (err) {
if (err instanceof StorageRevConflictError) {
ctx.logger.info('Save rev conflict, reloading from storage');
await this.loadFromStorageAndMerge(ctx);
return;
} else {
ctx.logger.info('Error saving data to storage');
throw err;
}
}
if (saveResult.rev) {
ctx.logger.info('Update rev in file info');
ctx.fileInfo.rev = saveResult.rev;
}
if (saveResult.path) {
ctx.logger.info('Update path in file info', saveResult.path);
ctx.file.path = saveResult.path;
ctx.fileInfo.path = saveResult.path;
ctx.path = saveResult.path;
}
ctx.file.syncDate = new Date();
ctx.logger.info('Save to storage complete, updated sync date');
// this.scheduleBackupFile(file, data); // TODO: backups
}
private async saveToCacheAndStorage(ctx: SyncContext) {
ctx.logger.info('Getting file data for saving');
const data = await ctx.file.getData();
if (ctx.storage.name === 'file') {
ctx.logger.info('Saving to file storage');
} else if (!ctx.file.dirty) {
ctx.logger.info('Saving to storage, skip cache because not dirty');
} else if (AppSettings.disableOfflineStorage) {
ctx.logger.info('Saving to storage, cache is disabled');
} else {
ctx.logger.info('Saving to cache');
await Storage.cache.save(ctx.file.id, data);
ctx.file.dirty = false;
ctx.logger.info('Saved to cache, saving to storage');
}
await this.saveToStorage(ctx, data);
}
private async loadFromStorageAndMerge(ctx: SyncContext) {
if (++ctx.retryCount === MaxLoadLoops) {
throw new Error('Too many load attempts');
}
ctx.logger.info('Load from storage, attempt', ctx.retryCount);
const storageLoadRes = await ctx.storage.load(ctx.path, ctx.opts);
ctx.logger.info('Load from storage', storageLoadRes.rev);
try {
await ctx.file.mergeOrUpdate(storageLoadRes.data);
ctx.logger.info('Merge complete OK');
} catch (err) {
ctx.logger.info('Merge error', err);
// this.refresh(); // TODO: trigger refresh
if (
err instanceof kdbxweb.KdbxError &&
err.code === kdbxweb.Consts.ErrorCodes.InvalidKey
) {
ctx.logger.info('Remote key changed, request to enter new key');
// Events.emit('remote-key-changed', { file }); // TODO: show the key change screen
}
throw err;
}
if (ctx.stat?.rev) {
ctx.logger.info('Update rev in file info');
ctx.fileInfo.rev = ctx.stat.rev;
}
ctx.file.syncDate = new Date();
if (ctx.file.modified) {
ctx.logger.info('Updated sync date, saving modified file');
await this.saveToCacheAndStorage(ctx);
} else if (ctx.file.dirty) {
if (AppSettings.disableOfflineStorage) {
ctx.logger.info('File is dirty and cache is disabled');
throw new Error('File is dirty and cache is disabled');
}
ctx.logger.info('Saving not modified dirty file to cache');
await Storage.cache.save(ctx.fileInfo.id, storageLoadRes.data);
ctx.file.dirty = false;
ctx.logger.info('Complete, remove dirty flag');
} else {
ctx.logger.info('Complete, no changes');
}
}
private async backupFile(file: File, data: ArrayBuffer): Promise<void> {
if (file.backupInProgress) {
return;
}
file.backupInProgress = true;
try {
const opts = file.opts;
const backup = file.backup;
const logger = new Logger('backup', file.name);
if (!backup || !backup.storage || !backup.path) {
throw new Error('Invalid backup settings');
}
const storage = Storage.get(backup.storage);
if (!storage) {
throw new Error(`Invalid backup storage: ${backup.storage}`);
}
let path = backup.path.replace('{date}', DateFormat.dtStrFs(new Date()));
logger.info('Backup file to', backup.storage, path);
let folderPath = UrlFormat.fileToDir(path);
if (storage.getPathForName) {
folderPath = storage.getPathForName(folderPath).replace('.kdbx', '');
}
try {
await storage.stat(folderPath, opts);
logger.info('Backup folder exists, saving');
} catch (err) {
if (err instanceof StorageFileNotFoundError) {
logger.info('Backup folder does not exist');
if (!storage.mkdir) {
throw new Error('Mkdir not supported by ' + backup.storage);
}
try {
await storage.mkdir(folderPath);
logger.info('Backup folder created');
} catch (err) {
logger.error('Error creating backup folder', err);
throw new Error('Error creating backup folder');
}
} else {
logger.error('Stat folder error', err);
throw new Error('Cannot stat backup folder');
}
}
if (storage.getPathForName) {
path = storage.getPathForName(path);
}
try {
await storage.save(path, data, opts);
} catch (err) {
logger.error('Backup error', err);
throw err;
}
logger.info('Backup complete');
backup.lastTime = Date.now();
file.backup = backup;
const fileInfo = FileManager.getFileInfoById(file.id);
if (fileInfo) {
fileInfo.backup = backup;
}
} finally {
file.backupInProgress = false;
}
}
private scheduleBackupFile(file: File, data: ArrayBuffer): void {
const backup = file.backup;
if (!backup || !backup.enabled || file.backupInProgress) {
return;
}
const logger = new Logger('backup', file.name);
let needBackup = false;
if (!backup.lastTime) {
needBackup = true;
logger.info('No last backup time, backup now');
} else {
const dt = new Date(backup.lastTime);
switch (backup.schedule) {
case '0':
break;
case '1d':
dt.setDate(dt.getDate() + 1);
break;
case '1w':
dt.setDate(dt.getDate() + 7);
break;
case '1m':
dt.setMonth(dt.getMonth() + 1);
break;
default:
return;
}
if (dt.getTime() <= Date.now()) {
needBackup = true;
}
const lastTimeStr = DateFormat.dtStrFs(backup.lastTime);
const dtStr = DateFormat.dtStrFs(dt);
logger.info(
`Last backup time: ${lastTimeStr}, schedule: ${backup.schedule}, ` +
`next time: ${dtStr}, ${needBackup ? 'backup now' : 'skip backup'}`
);
}
const fileInfo = FileManager.getFileInfoById(file.id);
if (fileInfo) {
fileInfo.backup = backup;
}
if (needBackup) {
this.backupFile(file, data).catch(noop);
}
}
deleteAllCachedFiles(): void {
for (const fileInfo of FileManager.fileInfos) {
if (fileInfo.storage && !fileInfo.modified) {
Storage.cache.remove(fileInfo.id).catch(noop);
}
}
}
deleteAllStoredTokens(): void {
for (const storage of Object.values(Storage.getAll())) {
storage.deleteStoredToken();
}
}
}
const instance = new FileController();
export { instance as FileController };
+26
View File
@@ -0,0 +1,26 @@
import { Logger } from 'util/logger';
const logger = new Logger('focus-manager');
class FocusManager {
private readonly _modalStack: string[] = [];
get modal(): string | undefined {
return this._modalStack[this._modalStack.length - 1];
}
pushModal(value: string): void {
this._modalStack.push(value);
logger.debug('Push modal', value);
}
popModal(): string | undefined {
const lastModal = this._modalStack.pop();
logger.debug('Pop modal', lastModal, '=>', this._modalStack[this._modalStack.length - 1]);
return lastModal;
}
}
const instance = new FocusManager();
export { instance as FocusManager };
+182
View File
@@ -0,0 +1,182 @@
import { AppSettings } from 'models/app-settings';
import { Locale } from 'util/locale';
import {
PasswordGeneratorAppSetting,
PasswordGeneratorOptions,
PasswordGeneratorPreset,
PasswordGeneratorCustomPreset
} from 'util/generators/password-generator';
export const GeneratorPresets = {
get defaultPreset(): PasswordGeneratorPreset {
return {
name: 'Default',
title: Locale.genPresetDefault,
builtIn: true,
length: 16,
upper: true,
lower: true,
digits: true
};
},
get browserExtensionPreset(): PasswordGeneratorOptions {
return {
name: 'BrowserExtension',
length: 20,
upper: true,
lower: true,
special: true,
brackets: true,
ambiguous: true
};
},
get builtIn(): PasswordGeneratorPreset[] {
return [
this.defaultPreset,
{
name: 'Pronounceable',
title: Locale.genPresetPronounceable,
builtIn: true,
length: 10,
lower: true,
upper: true
},
{
name: 'Med',
title: Locale.genPresetMed,
builtIn: true,
length: 16,
upper: true,
lower: true,
digits: true,
special: true,
brackets: true,
ambiguous: true
},
{
name: 'Long',
title: Locale.genPresetLong,
builtIn: true,
length: 32,
upper: true,
lower: true,
digits: true
},
{ name: 'Pin4', title: Locale.genPresetPin4, builtIn: true, length: 4, digits: true },
{
name: 'Mac',
title: Locale.genPresetMac,
builtIn: true,
length: 17,
include: '0123456789ABCDEF',
pattern: 'XX-'
},
{
name: 'Hash128',
title: Locale.genPresetHash128,
builtIn: true,
length: 32,
include: '0123456789abcdef'
},
{
name: 'Hash256',
title: Locale.genPresetHash256,
builtIn: true,
length: 64,
include: '0123456789abcdef'
}
];
},
get all(): PasswordGeneratorPreset[] {
let presets = this.builtIn;
const setting = AppSettings.generatorPresets;
if (setting) {
if (setting.user) {
presets = presets.concat(setting.user.map((item) => ({ ...item })));
}
let hasDefault = false;
presets.forEach((preset) => {
if (setting.disabled && setting.disabled[preset.name]) {
preset.disabled = true;
}
if (setting.default === preset.name) {
hasDefault = true;
preset.default = true;
}
});
if (!hasDefault) {
presets[0].default = true;
}
}
return presets;
},
get enabled(): PasswordGeneratorPreset[] {
const allPresets = this.all.filter((preset) => !preset.disabled);
if (!allPresets.length) {
allPresets.push(this.defaultPreset);
}
return allPresets;
},
getOrCreateSetting(): PasswordGeneratorAppSetting {
let setting = AppSettings.generatorPresets;
if (!setting) {
setting = { user: [], disabled: {} };
}
return setting;
},
add(preset: PasswordGeneratorCustomPreset): void {
const setting = this.getOrCreateSetting();
if (preset.name && !setting.user.filter((p) => p.name === preset.name).length) {
setting.user.push(preset);
this.save(setting);
}
},
remove(name: string): void {
const setting = this.getOrCreateSetting();
setting.user = setting.user.filter((p) => p.name !== name);
this.save(setting);
},
setPreset(name: string, props: Partial<PasswordGeneratorCustomPreset>): void {
const setting = this.getOrCreateSetting();
const preset = setting.user.filter((p) => p.name === name)[0];
if (preset) {
Object.assign(preset, props);
this.save(setting);
}
},
setDisabled(name: string, disabled: boolean): void {
const setting = this.getOrCreateSetting();
if (disabled) {
if (!setting.disabled) {
setting.disabled = {};
}
setting.disabled[name] = true;
} else if (setting.disabled) {
delete setting.disabled[name];
}
this.save(setting);
},
setDefault(name: string | null): void {
const setting = this.getOrCreateSetting();
if (name) {
setting.default = name;
} else {
delete setting.default;
}
this.save(setting);
},
save(setting: PasswordGeneratorAppSetting): void {
AppSettings.generatorPresets = { ...setting };
}
};
@@ -0,0 +1,63 @@
import { FileOpener } from 'util/browser/file-opener';
import { IconSelectState } from 'models/ui/icon-select-state';
import { Logger } from 'util/logger';
import { Events } from 'util/events';
import { IconUrlFormat } from 'util/formatting/icon-url-format';
const logger = new Logger('icon-select');
class IconSelectController {
openFile() {
FileOpener.open((file) => {
FileOpener.readBinary(file)
.then((fileData) => {
IconSelectState.selectedIconDataUrl =
IconUrlFormat.toDataUrl(fileData) ?? undefined;
})
.catch((ex) => logger.error('Error reading file', ex));
}, 'image/*');
}
downloadFavicon(websiteUrl: string): void {
if (IconSelectState.downloading) {
return;
}
IconSelectState.setDownloading();
const iconUrl = this.getIconUrl(websiteUrl);
const img = document.createElement('img');
img.crossOrigin = 'Anonymous';
img.src = iconUrl;
img.onload = () => {
IconSelectState.downloading = false;
logger.debug('Favicon downloaded', iconUrl);
const data = this.getIconData(img);
logger.debug(`Favicon data extracted: ${data.length} chars`);
Events.emit('custom-icon-downloaded', data);
};
img.onerror = (e) => {
logger.error('Favicon download error', iconUrl, e);
IconSelectState.setDownloadError();
};
}
private getIconUrl(websiteUrl: string): string {
const domain = websiteUrl.replace(/^.*:\/+/, '').replace(/\/.*/, '');
return 'https://services.keeweb.info/favicon/' + domain;
}
private getIconData(img: HTMLImageElement): string {
const size = Math.min(img.width, 32);
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = size;
canvas.height = size;
ctx?.drawImage(img, 0, 0, size, size);
return canvas.toDataURL().replace(/^.*,/, '');
}
}
const instance = new IconSelectController();
export { instance as IconSelectController };
+314
View File
@@ -0,0 +1,314 @@
import * as kdbxweb from 'kdbxweb';
import { FileManager } from 'models/file-manager';
import { Workspace } from 'models/workspace';
import { AppSettings } from 'models/app-settings';
import { FileOpener } from 'util/browser/file-opener';
import { Alerts } from 'comp/ui/alerts';
import { Locale } from 'util/locale';
import { errorToString } from 'util/fn';
import { DropboxChooser } from 'storage/dropbox-chooser';
import { Logger } from 'util/logger';
import { FileController } from 'comp/app/file-controller';
import { OpenState } from 'models/ui/open-state';
import { StorageBase } from 'storage/storage-base';
import { BrowserAuthStartedError, OAuthRejectedError, StorageListItem } from 'storage/types';
import { FunctionComponent, h } from 'preact';
import { OpenStorageFileList } from 'ui/open/open-storage-file-list';
import { UrlFormat } from 'util/formatting/url-format';
const logger = new Logger('open');
class OpenController {
open(): void {
if (OpenState.busy) {
return;
}
if (OpenState.id && FileManager.getFileById(OpenState.id)) {
Workspace.showList();
return;
}
OpenState.beginOpen();
FileController.open(OpenState)
.then(() => {
Workspace.showList();
})
.catch((err) => {
logger.error('Open error', err);
const invalidKey =
err instanceof kdbxweb.KdbxError &&
err.code === kdbxweb.Consts.ErrorCodes.InvalidKey;
OpenState.setOpenError(invalidKey);
if (!invalidKey) {
// } else if (err.userCanceled) { // TODO: yubikey cancellation
// if (err.notFound) { // TODO: handle file not found
// err = Locale.openErrorFileNotFound;
// }
const alertBody = Locale.openErrorDescription;
// if (err.maybeTouchIdChanged) { // TODO: handle touch ID
// alertBody += '\n' + Locale.openErrorDescriptionMaybeTouchIdChanged;
// }
Alerts.error({
header: Locale.openError,
body: alertBody,
pre: errorToString(err)
});
}
});
}
selectKeyFileFromDropbox(): void {
if (OpenState.busy || !AppSettings.canOpen) {
return;
}
const dropboxChooser = new DropboxChooser((err, res) => {
if (!err && res) {
OpenState.setKeyFile(res.name, res.data);
}
});
dropboxChooser.choose();
}
chooseFile(): void {
if (OpenState.busy || !AppSettings.canOpen) {
return;
}
FileOpener.open((file) => {
this.readFile(file).catch((e) => logger.error('Error selecting file', e));
});
}
async readFile(file: File): Promise<void> {
const fileData = await FileOpener.readBinary(file);
const format = OpenController.getOpenFileFormat(file, fileData);
switch (format) {
case 'kdbx': {
const name = file.name.replace(/\.kdbx$/i, '');
OpenState.setFile(
name,
fileData,
file.path || undefined,
file.path ? 'file' : undefined
);
break;
}
case 'xml': {
const name = file.name.replace(/\.\w+$/i, '');
const xml = kdbxweb.ByteUtils.bytesToString(fileData);
try {
await Workspace.importFileFromXml(name, xml);
} catch (e) {
logger.error('Error importing XML', e);
Alerts.error({
header: Locale.openXml,
body: Locale.openError,
pre: errorToString(e)
});
}
break;
}
case 'csv':
// TODO: load CSV
break;
case 'kdb':
Alerts.error({
header: Locale.openWrongFile,
body: Locale.openKdbFileBody
});
break;
default:
Alerts.error({
header: Locale.openWrongFile,
body: Locale.openWrongFileBody
});
break;
}
}
chooseKeyFile(): void {
if (OpenState.busy || !AppSettings.canOpen) {
return;
}
FileOpener.open((file) => {
this.readKeyFile(file).catch((e) => logger.error('Error selecting keyfile', e));
});
}
async readKeyFile(file: File): Promise<void> {
const keyFileData = await FileOpener.readBinary(file);
const path = AppSettings.rememberKeyFiles === 'path' && file.path ? file.path : undefined;
OpenState.setKeyFile(file.name, keyFileData, path);
}
readFileAndKeyFile(file: File, keyFile?: File): void {
this.readFile(file)
.then(() => {
if (keyFile) {
return this.readKeyFile(keyFile);
}
})
.catch((e) => {
logger.error('Error reading file and keyfile', e);
});
}
readDroppedFiles(files: File[]): void {
if (!files.length) {
return;
}
const dataFile = files.find((file) => /\.kdbx$/i.test(file.name));
const keyFile = files.find((file) => /\.keyx?$/i.test(file.name));
if (dataFile) {
this.readFileAndKeyFile(dataFile, keyFile);
return;
}
this.readFile(files[0]).catch((e) => logger.error('Error reading dropped files', e));
}
listStorage(storage: StorageBase, dir?: string, prevDir?: string): void {
if (OpenState.busy || !storage.list) {
return;
}
OpenState.setStorageProgress(storage.name);
storage
.list(dir)
.then((files) => {
OpenState.resetStorageProgress();
if (!files.length) {
Alerts.error({
header: Locale.openNothingFound,
body: Locale.openNothingFoundBody
});
return;
}
const collator = new Intl.Collator(undefined, { sensitivity: 'base' });
files.sort((x, y) => {
if (x.dir !== y.dir) {
return (y.dir ? 1 : 0) - (x.dir ? 1 : 0);
}
return collator.compare(x.path, y.path);
});
if (dir) {
files.unshift({
path: prevDir ?? '',
name: '..',
dir: true
});
}
this.showStorageFileListAlert(storage, files, dir);
})
.catch((e) => {
OpenState.resetStorageProgress();
if (e instanceof BrowserAuthStartedError || e instanceof OAuthRejectedError) {
return;
}
if (!Alerts.alertDisplayed) {
Alerts.error({
header: Locale.openError,
body: Locale.openListErrorBody,
pre: errorToString(e)
});
}
});
}
private showStorageFileListAlert(
storage: StorageBase,
files: StorageListItem[],
currentDir?: string
) {
const listView: FunctionComponent = () => {
const fileSelected = (file: StorageListItem) => {
if (file.dir) {
this.listStorage(storage, file.path, currentDir);
} else {
alert.closeWithResult('');
OpenState.setStorageFile(storage.name, {
path: file.path,
name: UrlFormat.getDataFileName(file.name),
rev: file.rev
});
}
};
return h(OpenStorageFileList, {
files,
fileSelected
});
};
const alert = Alerts.alert({
header: Locale.openSelectFile,
body: Locale.openSelectFileBody,
icon: storage.icon || 'file-alt',
buttons: [{ result: '', title: Locale.alertCancel }],
esc: '',
click: '',
view: listView
});
}
private static getOpenFileFormat(
file: File,
fileData: ArrayBuffer
): 'kdbx' | 'kdb' | 'xml' | 'csv' | undefined {
if (fileData.byteLength < 8) {
return undefined;
}
const fileSig = new Uint32Array(fileData, 0, 2);
if (fileSig[0] === kdbxweb.Consts.Signatures.FileMagic) {
if (fileSig[1] === kdbxweb.Consts.Signatures.Sig2Kdb) {
return 'kdb';
} else if (fileSig[1] === kdbxweb.Consts.Signatures.Sig2Kdbx) {
return 'kdbx';
} else {
return undefined;
}
} else if (AppSettings.canImportXml) {
try {
const str = kdbxweb.ByteUtils.bytesToString(fileSig).trim();
if (str.startsWith('<?xml')) {
return 'xml';
}
} catch (e) {}
return undefined;
} else if (AppSettings.canImportCsv && /\.csv$/i.test(file.name)) {
return 'csv';
} else {
return undefined;
}
}
private static async showLocalFileAlert(): Promise<void> {
if (AppSettings.skipOpenLocalWarn) {
return;
}
const res = await Alerts.alert({
header: Locale.openLocalFile,
body: Locale.openLocalFileBody,
icon: 'file-alt',
buttons: [
{ result: 'skip', title: Locale.openLocalFileDontShow, error: true },
{ result: 'ok', title: Locale.alertOk }
],
click: '',
esc: '',
enter: ''
}).wait();
if (res === 'skip') {
AppSettings.skipOpenLocalWarn = true;
}
}
}
const instance = new OpenController();
export { instance as OpenController };
+189
View File
@@ -0,0 +1,189 @@
import { Events } from 'util/events';
import { Shortcuts } from 'comp/browser/shortcuts';
import { Alert, Alerts } from 'comp/ui/alerts';
import { Features } from 'util/features';
import { Locale } from 'util/locale';
import { Logger } from 'util/logger';
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const QrCode = require('jsqrcode');
const logger = new Logger('otp-qr-reader');
class OtpQrReader {
private _alert?: Alert;
private _fileInput?: HTMLInputElement;
constructor() {
this.pasteEvent = this.pasteEvent.bind(this);
}
read() {
let screenshotKey = Shortcuts.screenshotToClipboardShortcut();
if (screenshotKey) {
screenshotKey = Locale.detSetupOtpAlertBodyWith.with(screenshotKey);
}
const pasteKey = Features.isMobile
? ''
: Locale.detSetupOtpAlertBodyWith.with(Shortcuts.actionShortcutSymbol() + 'V');
this.startListenClipboard();
const buttons = [
{ result: 'manually', title: Locale.detSetupOtpManualButton, silent: true },
Alerts.buttons.cancel
];
if (Features.isMobile) {
buttons.unshift({ result: 'select', title: Locale.detSetupOtpScanButton });
}
const line3 = Features.isMobile
? Locale.detSetupOtpAlertBody3Mobile
: Locale.detSetupOtpAlertBody3.with(pasteKey || '');
this._alert = Alerts.alert({
icon: 'qrcode',
header: Locale.detSetupOtpAlert,
body: [
Locale.detSetupOtpAlertBody,
Locale.detSetupOtpAlertBody1,
Locale.detSetupOtpAlertBody2.with(screenshotKey || ''),
line3,
Locale.detSetupOtpAlertBody4
].join('\n'),
esc: '',
click: '',
enter: '',
buttons,
complete: (res) => {
this._alert = undefined;
this.stopListenClipboard();
if (res === 'select') {
this.selectFile();
} else if (res === 'manually') {
this.enterManually();
}
}
});
}
selectFile() {
if (!this._fileInput) {
const input = document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('capture', 'camera');
input.setAttribute('accept', 'image/*');
input.setAttribute('class', 'hide-by-pos');
this._fileInput = input;
this._fileInput.onchange = () => this.fileSelected();
}
this._fileInput.click();
}
private fileSelected() {
const file = this._fileInput?.files?.[0];
if (!file || file.type.indexOf('image') < 0) {
return;
}
this.readFile(file);
}
private startListenClipboard() {
// eslint-disable-next-line @typescript-eslint/unbound-method
document.addEventListener('paste', this.pasteEvent);
}
private stopListenClipboard() {
// eslint-disable-next-line @typescript-eslint/unbound-method
document.removeEventListener('paste', this.pasteEvent);
}
private pasteEvent(e: ClipboardEvent) {
const items = e.clipboardData?.items;
if (!items) {
logger.info('Empty clipboard data');
return;
}
const item = [...items].find(
(item) => item.kind === 'file' && item.type.indexOf('image') !== -1
);
if (!item) {
logger.info('Paste without file');
return;
}
logger.info('Reading pasted image', item.type);
if (this._alert) {
this._alert.change({
header: Locale.detOtpImageReading
});
}
const file = item.getAsFile();
if (file) {
this.readFile(file);
} else {
logger.info('Empty file');
}
}
private readFile(file: File) {
const reader = new FileReader();
reader.onload = () => {
if (typeof reader.result !== 'string') {
logger.info('Read not a string');
return;
}
logger.info('Image data loaded');
this.readQr(reader.result);
};
reader.readAsDataURL(file);
}
private readQr(imageData: string) {
const image = new Image();
image.onload = () => {
logger.info('Image format loaded');
try {
const ts = logger.ts();
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-assignment
const url = new QrCode(image).decode();
logger.info('QR code read', logger.ts(ts));
this.removeAlert();
if (typeof url === 'string' && url) {
Events.emit('qr-url-read', url);
} else {
logger.error('Error reading QR code');
Alerts.error({
header: Locale.detOtpQrWrong,
body: Locale.detOtpQrWrongBody
});
}
} catch (e) {
logger.error('Error reading QR code', e);
this.removeAlert();
Alerts.error({
header: Locale.detOtpQrError,
body: Locale.detOtpQrErrorBody
});
}
};
image.onerror = () => {
logger.info('Image load error');
this.removeAlert();
Alerts.error({
header: Locale.detOtpImageError,
body: Locale.detOtpImageErrorBody
});
};
image.src = imageData;
}
private enterManually() {
Events.emit('qr-enter-manually');
}
private removeAlert() {
if (this._alert) {
this._alert.closeImmediate();
}
}
}
const instance = new OtpQrReader();
export { instance as OtpQrReader };
+472
View File
@@ -0,0 +1,472 @@
import * as kdbxweb from 'kdbxweb';
import { RuntimeInfo } from 'const/runtime-info';
import { Launcher } from 'comp/launcher';
import { Links } from 'const/links';
import { AppSettings } from 'models/app-settings';
import { SemVer } from 'util/data/semver';
import { Logger } from 'util/logger';
import { SignatureVerifier } from 'util/data/signature-verifier';
import { Model } from 'util/model';
import { Timeouts } from 'const/timeouts';
import { RuntimeData } from 'models/runtime-data';
import { noop } from 'util/fn';
import { StringFormat } from 'util/formatting/string-format';
import { ClientRequestArgs } from 'http';
import * as fs from 'fs';
import path from 'path';
import https from 'https';
const logger = new Logger('updater');
class Updater extends Model {
readonly enabled = Launcher?.updaterEnabled() ?? false;
status: 'unknown' | 'ready' | 'checking' | 'error' | 'ok' = 'unknown';
updateStatus:
| 'unknown'
| 'found'
| 'ready'
| 'downloading'
| 'extracting'
| 'updating'
| 'error' = 'unknown';
updateError?: string;
private _nextCheckTimeout?: number;
private _updateCheckDate = new Date(0);
init(): void {
this.scheduleNextCheck();
if (!Launcher && navigator.serviceWorker && !RuntimeInfo.beta && !RuntimeInfo.devMode) {
navigator.serviceWorker
.register('service-worker.js')
.then((reg) => {
logger.info('Service worker registered');
reg.addEventListener('updatefound', () => {
if (reg.active) {
logger.info('Service worker found an update');
this.updateStatus = 'ready';
}
});
})
.catch((e) => {
logger.error('Failed to register a service worker', e);
});
}
}
get updateInProgress(): boolean {
return (
this.status === 'checking' ||
['downloading', 'extracting', 'updating'].includes(this.updateStatus)
);
}
scheduleNextCheck(): void {
if (this._nextCheckTimeout) {
clearTimeout(this._nextCheckTimeout);
this._nextCheckTimeout = undefined;
}
if (!this.enabled || !AppSettings.autoUpdate) {
return;
}
let timeDiff = Timeouts.MinUpdateTimeout;
const lastCheckDate = RuntimeData.lastUpdateCheckDate;
if (lastCheckDate) {
timeDiff = Math.min(
Math.max(
Timeouts.UpdateInterval + (lastCheckDate.getTime() - Date.now()),
Timeouts.MinUpdateTimeout
),
Timeouts.UpdateInterval
);
}
this._nextCheckTimeout = window.setTimeout(() => {
this.check(false).catch(noop);
}, timeDiff);
logger.info(`Next update check will happen in ${Math.round(timeDiff / 1000)}s`);
}
async check(startedByUser: boolean) {
if (!this.enabled || this.updateInProgress) {
return;
}
this.status = 'checking';
if (!startedByUser) {
// additional protection from broken program logic, to ensure that auto-checks are not performed more than once an hour
const diffMs = Date.now() - this._updateCheckDate.getTime();
if (isNaN(diffMs) || diffMs < 1000 * 60 * 60) {
logger.error(
'Prevented update check; last check was performed at',
this._updateCheckDate
);
this.scheduleNextCheck();
return;
}
this._updateCheckDate = new Date();
}
logger.info('Checking for update...');
let data: Buffer | undefined;
try {
const httpRes = await this.httpGet({
url: Links.UpdateJson
});
data = httpRes.data;
} catch (e) {
logger.error('Update check error', e);
RuntimeData.batchSet(() => {
RuntimeData.lastUpdateCheckDate = new Date();
RuntimeData.lastUpdateCheckError = 'Error checking last version';
});
this.status = 'error';
this.scheduleNextCheck();
return;
}
let updateJson: Record<string, unknown>;
try {
const parsed = JSON.parse(data?.toString() || '') as unknown;
if (!parsed || typeof parsed !== 'object') {
throw new Error('Empty data');
}
updateJson = parsed as Record<string, unknown>;
} catch (e) {
logger.error('Failed to parse JSON', data);
return;
}
const updateVersion = updateJson.version;
const updateDate = new Date(String(updateJson.date));
const dt = new Date();
logger.info('Update check', updateVersion || 'no version', updateDate);
if (typeof updateVersion !== 'string' || !updateDate.getTime()) {
RuntimeData.batchSet(() => {
RuntimeData.lastUpdateCheckDate = dt;
RuntimeData.lastUpdateCheckError = 'Failed to parse update information';
});
this.status = 'error';
this.scheduleNextCheck();
return;
}
const prevLastVersion = RuntimeData.lastUpdateVersion;
RuntimeData.batchSet(() => {
RuntimeData.lastUpdateCheckDate = dt;
RuntimeData.lastSuccessUpdateCheckDate = dt;
RuntimeData.lastUpdateVersionReleaseDate = updateDate;
RuntimeData.lastUpdateVersion = updateVersion;
RuntimeData.lastUpdateCheckError = undefined;
});
this.status = 'ok';
this.scheduleNextCheck();
if (prevLastVersion === RuntimeData.lastUpdateVersion && this.updateStatus === 'ready') {
logger.info('Waiting for the user to apply downloaded update');
return;
}
if (!startedByUser && AppSettings.autoUpdate === 'install') {
await this.update();
} else if (SemVer.compareVersions(updateVersion, RuntimeInfo.version) > 0) {
this.updateStatus = 'found';
}
}
async updateAndRestart() {
await this.update();
await this.installAndRestart();
}
private async update() {
if (!this.enabled) {
logger.info('Updater is disabled');
return;
}
const ver = RuntimeData.lastUpdateVersion;
if (!ver) {
logger.info('No last update version');
return;
}
if (SemVer.compareVersions(RuntimeInfo.version, ver) >= 0) {
logger.info('You are using the latest version');
return;
}
this.batchSet(() => {
this.updateStatus = 'downloading';
this.updateError = undefined;
});
logger.info('Downloading update', ver);
const updateAssetName = this.getUpdateAssetName(ver);
if (!updateAssetName) {
logger.error('Empty updater asset name for', process.platform, process.arch);
return;
}
const updateUrlBasePath = Links.UpdateBasePath.replace('{ver}', ver);
const updateAssetUrl = updateUrlBasePath + updateAssetName;
let assetFilePath: string;
try {
const httpRes = await this.httpGet({
url: updateAssetUrl,
file: updateAssetName,
cleanupOldFiles: true,
cache: true
});
if (!httpRes.fileName) {
throw new Error('No fileName');
}
assetFilePath = httpRes.fileName;
} catch (e) {
logger.error('Error downloading update', e);
this.batchSet(() => {
this.updateStatus = 'error';
this.updateError = 'Error downloading update';
});
return;
}
logger.info('Downloading update signatures');
let assetFileSignaturePath: string;
try {
const httpRes = await this.httpGet({
url: updateUrlBasePath + 'Verify.sign.sha256',
file: updateAssetName + '.sign',
cleanupOldFiles: true,
cache: true
});
if (!httpRes.fileName) {
throw new Error('No fileName');
}
assetFileSignaturePath = httpRes.fileName;
} catch (e) {
logger.error('Error downloading update signatures', e);
this.batchSet(() => {
this.updateStatus = 'error';
this.updateError = 'Error downloading update signatures';
});
return;
}
let valid: boolean;
try {
valid = await this.verifySignature(assetFilePath, updateAssetName);
} catch (err) {
this.batchSet(() => {
this.updateStatus = 'error';
this.updateError = 'Error verifying update signature';
});
return;
}
if (!valid) {
this.batchSet(() => {
this.updateStatus = 'error';
this.updateError = 'Invalid update signature';
});
fs.unlink(assetFilePath, noop);
fs.unlink(assetFileSignaturePath, noop);
return;
}
logger.info('Update is ready', assetFilePath);
this.batchSet(() => {
this.updateStatus = 'ready';
this.updateError = undefined;
});
}
private async verifySignature(assetFilePath: string, assetName: string): Promise<boolean> {
logger.info('Verifying update signature', assetName);
const signaturesTxt = await fs.promises.readFile(assetFilePath + '.sign', 'utf8');
const assetSignatureLine = signaturesTxt
.split('\n')
.find((line) => line.endsWith(assetName));
if (!assetSignatureLine) {
logger.error('Signature not found for asset', assetName);
throw new Error('Asset signature not found');
}
const signature = kdbxweb.ByteUtils.hexToBytes(assetSignatureLine.split(' ')[0]);
const fileBytes = fs.readFileSync(assetFilePath);
try {
const valid = await SignatureVerifier.verify(fileBytes, signature);
logger.info(`Update asset signature is ${valid ? 'valid' : 'invalid'}`);
return valid;
} catch (e) {
logger.error('Error verifying signature', e);
throw e;
}
}
private getUpdateAssetName(ver: string): string | undefined {
const platform = process.platform;
const arch = process.arch;
switch (platform) {
case 'win32':
switch (arch) {
case 'x64':
return `KeeWeb-${ver}.win.x64.exe`;
case 'ia32':
return `KeeWeb-${ver}.win.ia32.exe`;
case 'arm64':
return `KeeWeb-${ver}.win.arm64.exe`;
}
break;
case 'darwin':
switch (arch) {
case 'x64':
return `KeeWeb-${ver}.mac.x64.dmg`;
case 'arm64':
return `KeeWeb-${ver}.mac.arm64.dmg`;
}
break;
}
return undefined;
}
async installAndRestart(): Promise<void> {
if (!Launcher || !RuntimeData.lastUpdateVersion) {
return;
}
const updateAssetName = this.getUpdateAssetName(RuntimeData.lastUpdateVersion);
const updateFilePath = await this.cacheFilePath(updateAssetName);
Launcher.requestRestartAndUpdate(updateFilePath);
}
async cacheFilePath(fileName?: string): Promise<string> {
const tempPath = await Launcher?.ipcRenderer.invoke('get-temp-path');
if (!tempPath) {
throw new Error('Failed to get temp path');
}
return fileName ? path.join(tempPath, fileName) : tempPath;
}
async httpGet(config: {
url: string;
file?: string;
cache?: boolean;
cleanupOldFiles?: boolean;
noRedirect?: boolean;
}): Promise<{ fileName?: string; data?: Buffer }> {
let tmpFile: string;
if (config.file) {
const baseTempPath = await this.cacheFilePath();
if (config.cleanupOldFiles) {
const allFiles = await fs.promises.readdir(baseTempPath);
for (const file of allFiles) {
if (
file !== config.file &&
StringFormat.replaceVersion(file, '0') ===
StringFormat.replaceVersion(config.file, '0')
) {
await fs.promises.unlink(path.join(baseTempPath, file));
}
}
}
tmpFile = path.join(baseTempPath, config.file);
let tmpFileExists = true;
try {
await fs.promises.access(tmpFile);
} catch {
tmpFileExists = false;
}
if (tmpFileExists) {
try {
if (config.cache && (await fs.promises.stat(tmpFile)).size > 0) {
logger.info('File already downloaded', config.url);
return Promise.resolve({ fileName: tmpFile });
} else {
await fs.promises.unlink(tmpFile);
}
} catch (e) {
fs.promises.unlink(tmpFile).catch(noop);
}
}
}
logger.info('GET ' + config.url);
const proxy = await Launcher?.ipcRenderer.invoke('resolve-proxy', config.url);
const url = new URL(config.url);
const opts: ClientRequestArgs = {
host: url.host,
port: url.port,
path: url.pathname + url.search
};
opts.headers = { 'User-Agent': navigator.userAgent };
logger.info(
'Request to ' +
config.url +
' ' +
(proxy ? `using proxy ${proxy.host}:${proxy.port}` : 'without proxy')
);
if (proxy) {
opts.headers.Host = url.host;
opts.host = proxy.host;
opts.port = proxy.port;
opts.path = config.url;
}
return new Promise((resolve, reject) => {
https
.get(opts, (res) => {
logger.info(`Response from ${config.url}: `, res.statusCode);
if (res.statusCode === 200) {
if (config.file) {
const file = fs.createWriteStream(tmpFile);
res.pipe(file);
file.on('finish', () => {
file.on('close', () => {
resolve({ fileName: tmpFile });
});
file.close();
});
file.on('error', (err) => {
reject(err);
});
} else {
const chunks: Buffer[] = [];
res.on('data', (chunk) => {
chunks.push(chunk);
});
res.on('end', () => {
resolve({ data: Buffer.concat(chunks) });
});
}
} else if (
res.headers.location &&
(res.statusCode === 301 || res.statusCode === 302)
) {
if (config.noRedirect) {
return reject(new Error('Too many redirects'));
}
config.url = res.headers.location;
config.noRedirect = true;
resolve(this.httpGet(config));
} else {
reject(new Error(`HTTP status ${res.statusCode ?? 0}`));
}
})
.on('error', (e) => {
logger.error('Cannot GET ' + config.url, e);
if (tmpFile) {
fs.unlink(tmpFile, noop);
}
reject(e);
});
});
}
}
const instance = new Updater();
export { instance as Updater };
-39
View File
@@ -1,39 +0,0 @@
const FeatureDetector = require('../util/feature-detector');
const Storage = require('../storage');
const AuthReceiver = {
receive: function() {
if (!FeatureDetector.isPopup && !FeatureDetector.isStandalone) {
return false;
}
const opener = window.opener || window.parent;
const message = this.urlArgsToMessage(window.location.href);
const hasKeys = Object.keys(message).filter(key => key !== 'config').length > 0;
if (!hasKeys) {
return false;
}
if (FeatureDetector.isStandalone) {
if (sessionStorage.authStorage) {
Storage[sessionStorage.authStorage].handleOAuthReturnMessage(message);
}
return false;
} else {
opener.postMessage(message, window.location.origin);
window.close();
return true;
}
},
urlArgsToMessage: function(url) {
const message = {};
url.split(/[?#&]/g).forEach(part => {
const parts = part.split('=');
if (parts.length === 2) {
message[parts[0]] = parts[1];
}
});
return message;
}
};
module.exports = AuthReceiver;
+79
View File
@@ -0,0 +1,79 @@
import { Events } from 'util/events';
import { Launcher } from 'comp/launcher';
import { AppSettings } from 'models/app-settings';
interface CopyPasteResult {
success: boolean;
seconds?: number;
}
const CopyPaste = {
copy(text: string): CopyPasteResult {
if (Launcher) {
Launcher.setClipboardText(text);
const clipboardSeconds = AppSettings.clipboardSeconds;
if (clipboardSeconds > 0) {
const clearClipboard = () => {
if (Launcher?.getClipboardText() === text) {
Launcher.clearClipboardText();
}
};
Events.on('main-window-will-close', clearClipboard);
setTimeout(() => {
clearClipboard();
Events.off('main-window-will-close', clearClipboard);
}, clipboardSeconds * 1000);
}
return { success: true, seconds: clipboardSeconds };
} else {
try {
if (document.execCommand('copy')) {
return { success: true };
}
} catch (e) {}
return { success: false };
}
},
createHiddenInput(text: string): void {
const hiddenInput = document.createElement('input');
hiddenInput.value = text;
hiddenInput.classList.add('hide-by-pos');
document.body.appendChild(hiddenInput);
hiddenInput.selectionStart = 0;
hiddenInput.selectionEnd = text.length;
hiddenInput.focus();
const onChange = () => {
setTimeout(() => hiddenInput.blur(), 0);
};
hiddenInput.addEventListener('cut', onChange);
hiddenInput.addEventListener('copy', onChange);
hiddenInput.addEventListener('paste', onChange);
hiddenInput.addEventListener('blur', () => hiddenInput.remove());
},
copyHtml(html: string): boolean {
const el = document.createElement('div');
el.style.userSelect = 'auto';
el.innerHTML = html;
document.body.appendChild(el);
const range = document.createRange();
range.selectNodeContents(el);
const sel = window.getSelection();
if (!sel) {
el.remove();
return false;
}
sel.removeAllRanges();
sel.addRange(range);
const result = document.execCommand('copy');
el.remove();
return result;
}
};
export { CopyPaste };
@@ -0,0 +1,39 @@
import { Events } from 'util/events';
import { Launcher } from 'comp/launcher';
import { Features } from 'util/features';
const FocusDetector = {
isFocused: false,
detectsFocusWithEvents: false,
init(): void {
this.isFocused = true;
this.detectsFocusWithEvents = !Features.isDesktop && !Features.isMobile;
if (this.detectsFocusWithEvents) {
window.addEventListener('focus', () => {
if (!FocusDetector.isFocused) {
FocusDetector.isFocused = true;
Events.emit('main-window-focus');
}
});
window.addEventListener('blur', () => {
if (FocusDetector.isFocused) {
FocusDetector.isFocused = false;
Events.emit('main-window-blur');
}
});
}
},
hasFocus(): Promise<boolean> {
if (this.detectsFocusWithEvents) {
return Promise.resolve(this.isFocused);
} else if (Launcher) {
return Launcher.ipcRenderer.invoke('is-app-focused');
} else {
return Promise.resolve(true);
}
}
};
export { FocusDetector };
+24
View File
@@ -0,0 +1,24 @@
import { Events } from 'util/events';
import { AppSettings } from 'models/app-settings';
const IdleTracker = {
actionTime: Date.now(),
init(): void {
setInterval(this.checkIdle.bind(this), 1000 * 60);
},
checkIdle(): void {
const idleMinutes = (Date.now() - this.actionTime) / 1000 / 60;
const maxIdleMinutes = AppSettings.idleMinutes;
if (maxIdleMinutes && idleMinutes > maxIdleMinutes) {
Events.emit('before-user-idle');
Events.emit('user-idle');
}
},
regUserAction(): void {
this.actionTime = Date.now();
}
};
Events.on('power-monitor-resume', () => IdleTracker.checkIdle());
export { IdleTracker };
+156
View File
@@ -0,0 +1,156 @@
import { Events } from 'util/events';
import { IdleTracker } from 'comp/browser/idle-tracker';
import { Keys } from 'const/keys';
import { FocusManager } from 'comp/app/focus-manager';
const shortcutKeyProp = navigator.platform.indexOf('Mac') >= 0 ? 'metaKey' : 'ctrlKey';
interface ShortcutDef {
handler: (e: KeyboardEvent, code: number) => void;
shortcut?: number;
modal?: string;
noPrevent?: boolean;
}
class KeyHandler {
SHORTCUT_ACTION = 1;
SHORTCUT_OPT = 2;
SHORTCUT_SHIFT = 4;
shortcuts = new Map<Keys, ShortcutDef[]>();
init() {
document.addEventListener('keypress', (e) => this.keypress(e));
document.addEventListener('keydown', (e) => this.keydown(e));
this.shortcuts.set(Keys.DOM_VK_A, [
{
handler: (e) => this.handleAKey(e),
shortcut: this.SHORTCUT_ACTION,
modal: '*',
noPrevent: true
}
]);
}
onKey(
key: Keys,
handler: (e: KeyboardEvent) => void,
shortcut?: number,
modal?: string,
noPrevent?: boolean
): () => void {
let keyShortcuts = this.shortcuts.get(key);
if (!keyShortcuts) {
keyShortcuts = [];
this.shortcuts.set(key, keyShortcuts);
}
const def: ShortcutDef = {
handler,
shortcut,
modal,
noPrevent
};
keyShortcuts.push(def);
return () => {
const keyShortcuts = this.shortcuts.get(key);
if (keyShortcuts) {
const ix = keyShortcuts.indexOf(def);
if (ix >= 0) {
keyShortcuts.splice(ix, 1);
}
}
};
}
isActionKey(e: KeyboardEvent): boolean {
return e[shortcutKeyProp];
}
keydown(e: KeyboardEvent): void {
IdleTracker.regUserAction();
const code = e.keyCode || e.which;
const keyShortcuts = this.shortcuts.get(code);
if (keyShortcuts && keyShortcuts.length) {
for (const sh of keyShortcuts) {
if (FocusManager.modal && sh.modal !== FocusManager.modal && sh.modal !== '*') {
e.stopPropagation();
continue;
}
const isActionKey = this.isActionKey(e);
switch (sh.shortcut) {
case this.SHORTCUT_ACTION:
if (!isActionKey) {
continue;
}
break;
case this.SHORTCUT_OPT:
if (!e.altKey) {
continue;
}
break;
case this.SHORTCUT_SHIFT:
if (!e.shiftKey) {
continue;
}
break;
case this.SHORTCUT_ACTION + this.SHORTCUT_OPT:
if (!e.altKey || !isActionKey) {
continue;
}
break;
default:
if (e.metaKey || e.ctrlKey || e.altKey || e.shiftKey) {
continue;
}
break;
}
let immediatePropagationStopped = false;
e.stopImmediatePropagation = () => {
immediatePropagationStopped = true;
KeyboardEvent.prototype.stopImmediatePropagation.call(e);
};
sh.handler(e, code);
if (isActionKey && !sh.noPrevent) {
e.preventDefault();
}
if (immediatePropagationStopped) {
break;
}
}
}
}
keypress(e: KeyboardEvent): void {
if (
!FocusManager.modal &&
e.which !== Keys.DOM_VK_RETURN &&
e.which !== Keys.DOM_VK_ESCAPE &&
e.which !== Keys.DOM_VK_TAB &&
!e.altKey &&
!e.ctrlKey &&
!e.metaKey
) {
Events.emit('keypress', e);
} else if (FocusManager.modal) {
Events.emit('keypress-modal', e, FocusManager.modal);
}
}
reg() {
IdleTracker.regUserAction();
}
handleAKey(e: KeyboardEvent): void {
if (e.target instanceof HTMLInputElement && ['password', 'text'].includes(e.target.type)) {
e.stopImmediatePropagation();
} else {
e.preventDefault();
}
}
}
const instance = new KeyHandler();
export { instance as KeyHandler };
@@ -0,0 +1,65 @@
import { Events } from 'util/events';
import { Launcher } from 'comp/launcher';
import { Alerts } from 'comp/ui/alerts';
import { Timeouts } from 'const/timeouts';
import { Locale } from 'util/locale';
const PopupNotifier = {
init(): void {
if (Launcher) {
window.open = () => null;
} else {
const windowOpen = window.open;
window.open = function (...args) {
const win = windowOpen.apply(window, args);
if (win) {
PopupNotifier.deferCheckClosed(win);
Events.emit('popup-opened', win);
} else if (!Alerts.alertDisplayed) {
Alerts.error({
header: Locale.authPopupRequired,
body: Locale.authPopupRequiredBody
});
}
return win;
};
}
},
deferCheckClosed(win: Window): void {
setTimeout(PopupNotifier.checkClosed.bind(PopupNotifier, win), Timeouts.CheckWindowClosed);
},
checkClosed(win: Window): void {
if (win.closed) {
setTimeout(
PopupNotifier.triggerClosed.bind(PopupNotifier, win),
Timeouts.CheckWindowClosed
);
} else {
const loc = PopupNotifier.tryGetLocationSearch(win);
if (loc) {
try {
win.close();
} catch {}
PopupNotifier.triggerClosed(win, loc);
return;
}
PopupNotifier.deferCheckClosed(win);
}
},
tryGetLocationSearch(win: Window): string | undefined {
try {
if (win.location.host === location.host) {
return win.location.search;
}
} catch {}
},
triggerClosed(window: Window, locationSearch?: string): void {
Events.emit('popup-closed', window, locationSearch);
}
};
export { PopupNotifier };
+160
View File
@@ -0,0 +1,160 @@
import { Launcher } from 'comp/launcher';
import { Keys } from 'const/keys';
import { AppSettingsFieldName, AppSettings } from 'models/app-settings';
import { Features } from 'util/features';
import { Locale } from 'util/locale';
let allowedKeys: Map<number, string>;
function getAllowedKeys(): Map<number, string> {
if (!allowedKeys) {
allowedKeys = new Map<number, string>();
for (const [name, code] of Object.entries(Keys)) {
if (typeof code === 'string') {
continue;
}
const keyName = name.replace('DOM_VK_', '');
if (/^([0-9A-Z]|F\d{1,2})$/.test(keyName)) {
allowedKeys.set(code, keyName);
}
}
}
return allowedKeys;
}
const AllGlobalShortcuts = {
copyPassword: { mac: 'Ctrl+Alt+C', all: 'Shift+Alt+C' },
copyUser: { mac: 'Ctrl+Alt+B', all: 'Shift+Alt+B' },
copyUrl: { mac: 'Ctrl+Alt+U', all: 'Shift+Alt+U' },
copyOtp: undefined,
autoType: { mac: 'Ctrl+Alt+T', all: 'Shift+Alt+T' },
restoreApp: undefined
};
export type GlobalShortcutType = keyof typeof AllGlobalShortcuts;
const GlobalShortcutAppSettingsFields: Record<GlobalShortcutType, AppSettingsFieldName> = {
copyPassword: 'globalShortcutCopyPassword',
copyUser: 'globalShortcutCopyUser',
copyUrl: 'globalShortcutCopyUrl',
copyOtp: 'globalShortcutCopyOtp',
autoType: 'globalShortcutAutoType',
restoreApp: 'globalShortcutRestoreApp'
};
const Shortcuts = {
keyEventToShortcut(event: KeyboardEvent): { valid: boolean; value: string } {
const modifiers = [];
if (event.ctrlKey) {
modifiers.push('Ctrl');
}
if (event.altKey) {
modifiers.push('Alt');
}
if (event.shiftKey) {
modifiers.push('Shift');
}
if (Features.isMac && event.metaKey) {
modifiers.push('Meta');
}
const keyName = getAllowedKeys().get(event.which);
return {
value: modifiers.join('+') + '+' + (keyName || '…'),
valid: modifiers.length > 0 && !!keyName
};
},
presentShortcut(shortcutValue: string | undefined, formatting?: boolean): string {
if (!shortcutValue) {
return '-';
}
return shortcutValue
.split(/\+/g)
.map((part) => {
switch (part) {
case 'Ctrl':
return this.ctrlShortcutSymbol(formatting);
case 'Alt':
return this.altShortcutSymbol(formatting);
case 'Shift':
return this.shiftShortcutSymbol(formatting);
case 'Meta':
return this.actionShortcutSymbol(formatting);
default:
return part;
}
})
.join('');
},
actionShortcutSymbol(formatting?: boolean): string {
return Features.isMac ? '⌘' : this.formatShortcut(Locale.ctrlKey, formatting);
},
altShortcutSymbol(formatting?: boolean): string {
return Features.isMac ? '⌥' : this.formatShortcut(Locale.altKey, formatting);
},
shiftShortcutSymbol(formatting?: boolean): string {
return Features.isMac ? '⇧' : this.formatShortcut(Locale.shiftKey, formatting);
},
ctrlShortcutSymbol(formatting?: boolean): string {
return Features.isMac ? '⌃' : this.formatShortcut(Locale.ctrlKey, formatting);
},
formatShortcut(shortcut: string, formatting?: boolean): string {
return formatting ? `${shortcut} + ` : `${shortcut}+`;
},
globalShortcutText(type: GlobalShortcutType, formatting?: boolean): string {
return this.presentShortcut(this.globalShortcut(type), formatting);
},
globalShortcut(type: GlobalShortcutType): string | undefined {
const setting = GlobalShortcutAppSettingsFields[type];
const appSettingsShortcut = AppSettings[setting];
if (typeof appSettingsShortcut === 'string') {
return appSettingsShortcut;
}
const globalShortcut = AllGlobalShortcuts[type];
if (globalShortcut) {
if (Features.isMac && globalShortcut.mac) {
return globalShortcut.mac;
}
return globalShortcut.all;
}
return undefined;
},
setGlobalShortcut(type: GlobalShortcutType, value: string | null): void {
if (!AllGlobalShortcuts[type]) {
throw new Error('Bad shortcut: ' + type);
}
const setting = GlobalShortcutAppSettingsFields[type];
if (value) {
AppSettings.set(setting, value);
} else {
AppSettings.delete(setting);
}
Launcher?.ipcRenderer.invoke('set-global-shortcuts', { [setting]: value });
},
screenshotToClipboardShortcut(): string {
if (Features.isiOS) {
return 'Sleep+Home';
}
if (Features.isMobile) {
return '';
}
if (Features.isMac) {
return 'Command-Shift-Control-4';
}
if (Features.isWindows) {
return 'Alt+PrintScreen';
}
return '';
}
};
export { Shortcuts };
@@ -1,5 +1,5 @@
const Backbone = require('backbone');
const Launcher = require('./launcher');
import { Events } from 'util/events';
import { Launcher } from 'comp/launcher';
const LocalStorageKeyName = 'instanceCheck';
const LocalStorageResponseKeyName = 'instanceMaster';
@@ -7,32 +7,39 @@ const LocalStorageResponseKeyName = 'instanceMaster';
const instanceKey = Date.now().toString();
const SingleInstanceChecker = {
init: function() {
init(): void {
if (Launcher) {
return;
}
// eslint-disable-next-line @typescript-eslint/unbound-method
window.addEventListener('storage', SingleInstanceChecker.storageChanged);
SingleInstanceChecker.setKey(LocalStorageKeyName, instanceKey);
},
storageChanged: function(e) {
storageChanged(e: StorageEvent): void {
if (!e.newValue) {
return;
}
if (e.key === LocalStorageKeyName && e.newValue !== instanceKey) {
SingleInstanceChecker.setKey(LocalStorageResponseKeyName, instanceKey + Math.random().toString());
SingleInstanceChecker.setKey(
LocalStorageResponseKeyName,
instanceKey + Math.random().toString()
);
} else if (e.key === LocalStorageResponseKeyName && e.newValue.indexOf(instanceKey) < 0) {
// eslint-disable-next-line @typescript-eslint/unbound-method
window.removeEventListener('storage', SingleInstanceChecker.storageChanged);
Backbone.trigger('second-instance');
Events.emit('second-instance');
}
},
setKey: function(key, value) {
setKey(key: string, value: string): void {
try {
localStorage.setItem(key, value);
setTimeout(() => { localStorage.removeItem(key); }, 100);
setTimeout(() => {
localStorage.removeItem(key);
}, 100);
} catch (e) {}
}
};
module.exports = SingleInstanceChecker;
export { SingleInstanceChecker };
+19
View File
@@ -0,0 +1,19 @@
import { Events } from 'util/events';
const ThemeWatcher = {
dark: false,
init(): void {
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
if (mediaQuery && mediaQuery.addEventListener) {
mediaQuery.addEventListener('change', (e) => {
const dark = e.matches;
this.dark = dark;
Events.emit('dark-mode-changed', dark);
});
}
this.dark = mediaQuery.matches;
}
};
export { ThemeWatcher };
+42
View File
@@ -0,0 +1,42 @@
import { Features } from 'util/features';
import { AppSettings } from 'models/app-settings';
import { Events } from 'util/events';
export const WindowClass = {
init(): void {
const browserCssClass = Features.browserCssClass;
if (browserCssClass) {
document.body.classList.add(browserCssClass);
}
if (AppSettings.titlebarStyle !== 'default') {
document.body.classList.add(`titlebar-${AppSettings.titlebarStyle}`);
if (Features.renderCustomTitleBar) {
document.body.classList.add('titlebar-custom');
}
}
if (Features.isMobile) {
document.body.classList.add('mobile');
}
Events.on('enter-full-screen', () => document.body.classList.add('fullscreen'));
Events.on('leave-full-screen', () => document.body.classList.remove('fullscreen'));
},
setThemeClass(theme: string): void {
for (const cls of document.body.classList) {
if (cls.startsWith('th-')) {
document.body.classList.remove(cls);
}
}
document.body.classList.add(`th-${theme}`);
},
setFontSizeClass(fontSize: number): void {
for (const cls of document.body.classList) {
if (cls.startsWith('font-size-')) {
document.body.classList.remove(cls);
}
}
document.body.classList.add(`font-size-${fontSize}`);
}
};
@@ -0,0 +1,80 @@
import { ContextMenu, ContextMenuItem } from 'models/menu/context-menu';
import { StringFormat } from 'util/formatting/string-format';
import { Locale } from 'util/locale';
import { Features } from 'util/features';
import { Shortcuts } from 'comp/browser/shortcuts';
import { Position } from 'util/types';
import { FileManager } from 'models/file-manager';
import { Entry } from 'models/entry';
import { File } from 'models/file';
export class ContextMenuNew {
static show(pos: Position): void {
const newEntryMenuItem = new ContextMenuItem(
'entry',
'key',
StringFormat.capFirst(Locale.entry),
() => this.newEntryClicked()
);
if (!Features.isMobile) {
const shortcut = Shortcuts.presentShortcut('Alt+N');
newEntryMenuItem.hint = `(${Locale.searchShiftClickOr} ${shortcut})`;
}
const newGroupMenuItem = new ContextMenuItem(
'group',
'folder',
StringFormat.capFirst(Locale.group),
() => this.newGroupClicked()
);
const templateMenuItems: ContextMenuItem[] = [];
const hasMultipleFiles = FileManager.files.length > 1;
for (const file of FileManager.files) {
for (const entry of file.allEntryTemplates()) {
if (!entry.title) {
continue;
}
const id = `tmpl:${entry.id}`;
templateMenuItems.push(
new ContextMenuItem(
id,
entry.icon ?? 'sticky-note-o',
hasMultipleFiles ? `${file.name} / ${entry.title}` : entry.title,
() => this.newFromTemplateClicked(entry, file)
)
);
}
}
const collator = new Intl.Collator(undefined, { sensitivity: 'base' });
templateMenuItems.sort((x, y) => {
return collator.compare(x.title, y.title);
});
templateMenuItems.push(
new ContextMenuItem(
'tmpl',
'sticky-note-o',
StringFormat.capFirst(Locale.template),
() => this.newTemplateClicked()
)
);
ContextMenu.toggle('new', pos, [newEntryMenuItem, newGroupMenuItem, ...templateMenuItems]);
}
static newEntryClicked(): void {
// TODO
}
static newGroupClicked(): void {
// TODO
}
static newTemplateClicked(): void {
// TODO
}
static newFromTemplateClicked(entry: Entry, file: File): void {
// TODO
}
}
@@ -0,0 +1,92 @@
import { ContextMenu, ContextMenuItem } from 'models/menu/context-menu';
import { Position } from 'util/types';
import { StringFormat } from 'util/formatting/string-format';
import { Locale } from 'util/locale';
import { QuerySort } from 'models/query';
import { Workspace } from 'models/workspace';
const arrow = '→';
export class ContextMenuSort {
static show(pos: Position): void {
const items: ContextMenuItem[] = [
new ContextMenuItem(
QuerySort.TitleAsc,
'sort-alpha-down',
StringFormat.capFirst(Locale.title) + ' ' + Locale.searchAZ.with(arrow),
() => this.itemClicked(QuerySort.TitleAsc)
),
new ContextMenuItem(
QuerySort.TitleDesc,
'sort-alpha-down-alt',
StringFormat.capFirst(Locale.title) + ' ' + Locale.searchZA.with(arrow),
() => this.itemClicked(QuerySort.TitleDesc)
),
new ContextMenuItem(
QuerySort.WebsiteAsc,
'sort-alpha-down',
StringFormat.capFirst(Locale.website) + ' ' + Locale.searchAZ.with(arrow),
() => this.itemClicked(QuerySort.WebsiteAsc)
),
new ContextMenuItem(
QuerySort.WebsiteDesc,
'sort-alpha-down-alt',
StringFormat.capFirst(Locale.website) + ' ' + Locale.searchZA.with(arrow),
() => this.itemClicked(QuerySort.WebsiteDesc)
),
new ContextMenuItem(
QuerySort.UserAsc,
'sort-alpha-down',
StringFormat.capFirst(Locale.user) + ' ' + Locale.searchAZ.with(arrow),
() => this.itemClicked(QuerySort.UserAsc)
),
new ContextMenuItem(
QuerySort.UserDesc,
'sort-alpha-down-alt',
StringFormat.capFirst(Locale.user) + ' ' + Locale.searchZA.with(arrow),
() => this.itemClicked(QuerySort.UserDesc)
),
new ContextMenuItem(
QuerySort.CreatedAsc,
'sort-numeric-down',
StringFormat.capFirst(Locale.searchCreated) + ' ' + Locale.searchON.with(arrow),
() => this.itemClicked(QuerySort.CreatedAsc)
),
new ContextMenuItem(
QuerySort.CreatedDesc,
'sort-numeric-down-alt',
StringFormat.capFirst(Locale.searchCreated) + ' ' + Locale.searchNO.with(arrow),
() => this.itemClicked(QuerySort.CreatedDesc)
),
new ContextMenuItem(
QuerySort.UpdatedAsc,
'sort-numeric-down',
StringFormat.capFirst(Locale.searchUpdated) + ' ' + Locale.searchON.with(arrow),
() => this.itemClicked(QuerySort.UpdatedAsc)
),
new ContextMenuItem(
QuerySort.UpdatedDesc,
'sort-numeric-down-alt',
StringFormat.capFirst(Locale.searchUpdated) + ' ' + Locale.searchNO.with(arrow),
() => this.itemClicked(QuerySort.UpdatedDesc)
),
new ContextMenuItem(
QuerySort.AttachmentsDesc,
'sort-amount-down',
Locale.searchAttachments,
() => this.itemClicked(QuerySort.AttachmentsDesc)
),
new ContextMenuItem(QuerySort.RankDesc, 'sort-amount-down', Locale.searchRank, () =>
this.itemClicked(QuerySort.RankDesc)
)
];
const selectedItem = items.find((it) => it.id === Workspace.query.sort);
ContextMenu.toggle('sort', pos, items, selectedItem);
}
private static itemClicked(sort: QuerySort) {
Workspace.query.sort = sort;
}
}

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