Compare commits

...
46 Commits
Author SHA1 Message Date
antelle dfc6201285 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-07-18 16:21:23 +02:00
antelle 1930c265c8 Merge branch 'master' into release-1.18 2021-07-18 16:21:06 +02:00
antelle 1c434d7c79 release notes 2021-07-18 16:20:52 +02:00
antelle c0c75ac8a8 Merge branch 'master' into release-1.18 2021-07-18 16:19:59 +02:00
antelle 4b7124aa57 disabled automatic installation of KeePassXC-Browser extension 2021-07-18 16:19:28 +02:00
antelle 93cee76b4f up translations 2021-07-18 16:09:59 +02:00
antelle 1673580dfa bump version 2021-07-18 16:06:15 +02:00
antelle bf0e94582d release notes 2021-07-18 16:06:14 +02:00
antelle 29ae7e8ed2 fix #1845: fixed an error during writing to closed socket 2021-07-18 16:06:13 +02:00
antelle 9b2c40a078 added yubikeys code logging 2021-07-18 16:06:12 +02:00
antelle f0bb382449 fixed variable usage 2021-07-18 16:06:11 +02:00
antelle 062ddb3f72 added MS Teams apps 2021-07-18 16:06:10 +02:00
antelle 208a1b551e renames some ms teams constants 2021-07-18 16:06:09 +02:00
Saulo Alves f8af64e45b renamed teams to microsoft teams; fixed grunt prettier error in onedrive 2021-07-18 16:06:08 +02:00
Saulo Alves 98268f21c0 added teams storage; added tenant id configuration for onedrive and teams 2021-07-18 16:06:07 +02:00
antelle dcbe8d70da fixed donate button border 2021-07-18 16:06:06 +02:00
Dimitri Witkowski 1d61c6ca03 Merge pull request #1838 from magnetikonline/fix-keeweb-connect-extension-link
Fix broken links to download the KeeWeb Connect browser extension
2021-06-19 20:12:38 +02:00
Peter Mescalchin 433f0acf3c fix broken links to download KeeWeb Connect browser extension due to incorrect const/Links property 2021-06-05 15:11:53 +10: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 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 4fb25451a2 fix #1816: old Chromium support, such as Android Edge 2021-05-13 10:45:48 +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 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 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 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
33 changed files with 711 additions and 112 deletions
+2
View File
@@ -7,6 +7,8 @@
}],
"@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 -1
View File
@@ -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?
+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: 'teams', search: location.search },
window.location.origin
);
window.close();
</script>
</body>
</html>
+14 -1
View File
@@ -246,7 +246,7 @@ const AutoType = {
},
processEventWithFilter(evt) {
const entries = evt.filter.getEntries();
let entries = evt.filter.getEntries();
if (entries.length === 1 && AppSettingsModel.directAutotype) {
this.hideWindow(() => {
this.runAndHandleResult({ entry: entries[0] }, evt.windowInfo.id);
@@ -255,6 +255,19 @@ const AutoType = {
}
this.focusMainWindow();
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)
+4
View File
@@ -209,6 +209,10 @@ const YubiKey = {
complete: (err, stdout) => {
this.process = null;
if (window.debugYubiKey) {
logger.info('received codes', err, stdout);
}
if (this.aborted) {
return callback('Aborted');
}
+3 -5
View File
@@ -325,7 +325,7 @@ async function findEntry(request, returnIfOneMatch, filterOptions) {
if (!entries.length) {
if (AppSettingsModel.extensionFocusIfEmpty) {
filter.useUrl = false;
if (filter.title) {
if (filter.title && AppSettingsModel.autoTypeTitleFilterEnabled) {
filter.useTitle = true;
entries = filter.getEntries();
if (!entries.length) {
@@ -522,7 +522,7 @@ const ProtocolHandlers = {
}
const otpPromise = new Promise((resolve, reject) => {
selectEntryFieldView.on('result', () => reject(makeError(Errors.userRejected)));
selectEntryFieldView?.on('result', () => reject(makeError(Errors.userRejected)));
entry.otpGenerator.next((err, otp) => {
if (otp) {
resolve(otp);
@@ -536,9 +536,7 @@ const ProtocolHandlers = {
try {
totp = await otpPromise;
} finally {
if (selectEntryFieldView) {
selectEntryFieldView.remove();
}
selectEntryFieldView?.remove();
}
return encryptResponse(request, {
@@ -191,7 +191,7 @@ const Launcher = {
}
},
quitOnRealQuitEventIfMinimizeOnQuitIsEnabled() {
return !!(this.platform() === 'darwin' || this.pendingUpdateFile);
return !!this.pendingUpdateFile;
},
minimizeApp() {
this.remoteApp().minimizeApp({
+14 -1
View File
@@ -37,4 +37,17 @@ const OneDriveApps = {
}
};
export { DropboxApps, GDriveApps, OneDriveApps };
const MsTeamsApps = {
Local: {
id: '8fbe2245-13d5-446f-bedc-74c3b2e1f635'
},
Production: {
id: '8fbe2245-13d5-446f-bedc-74c3b2e1f635'
},
Desktop: {
id: '8fbe2245-13d5-446f-bedc-74c3b2e1f635',
secret: 'F02~HYaWs-~7MndJcVRtv9~h-50Brk_9ho'
}
};
export { DropboxApps, GDriveApps, OneDriveApps, MsTeamsApps };
+8 -1
View File
@@ -18,6 +18,7 @@ const DefaultAppSettings = {
colorfulIcons: false, // use colorful custom icons instead of grayscale
useMarkdown: true, // use Markdown in Notes field
directAutotype: true, // if only one matching entry is found, select that one automatically
autoTypeTitleFilterEnabled: true, // enable the title filtering in auto-type by default
titlebarStyle: 'default', // window titlebar style
lockOnMinimize: true, // lock the app when it's minimized
lockOnCopy: false, // lock the app after a password was copied
@@ -86,7 +87,13 @@ const DefaultAppSettings = {
onedrive: true, // enable OneDrive integration
onedriveClientId: null, // custom OneDrive client id
onedriveClientSecret: null // custom OneDrive client secret
onedriveClientSecret: null, // custom OneDrive client secret
onedriveTenantId: null, // custom OneDrive tenant id
msteams: false, // enable Microsoft Teams integration
msteamsClientId: null, // custom Microsoft Teams client id
msteamsClientSecret: null, // custom Microsoft Teams client secret
msteamsTenantId: null // custom Microsoft Teams tenant id
};
export { DefaultAppSettings };
+3 -6
View File
@@ -23,17 +23,14 @@ const Links = {
HaveIBeenPwnedPrivacy: 'https://haveibeenpwned.com/Passwords',
ExtensionHelpForOtherBrowsers:
'https://github.com/keeweb/keeweb/wiki/Browser-AutoFill#other-browsers',
ExtensionHelpForKPXC:
'https://github.com/keeweb/keeweb/wiki/Browser-AutoFill#keepassxc-browser',
KWCForChrome:
'https://chrome.google.com/webstore/detail/keeweb-connect/pikpfmjfkekaeinceagbebpfkmkdlcjk',
KWCForFirefox: 'https://addons.mozilla.org/firefox/addon/keeweb-connect/',
KWCForEdge:
'https://microsoftedge.microsoft.com/addons/detail/keewebconnect/nmggpehkjmeaeocmaijenpejbepckinm',
KWCForSafari: 'https://apps.apple.com/app/keeweb-connect/id1565748094',
KPXCForChrome:
'https://chrome.google.com/webstore/detail/keepassxc-browser/oboonakemofpalcgghocfoadofidjkkk',
KPXCForFirefox: 'https://addons.mozilla.org/firefox/addon/keepassxc-browser/',
KPXCForEdge:
'https://microsoftedge.microsoft.com/addons/detail/keepassxcbrowser/pdffhmdngciaglkoonimfcmckehcpafo'
KWCForSafari: 'https://apps.apple.com/app/keeweb-connect/id1565748094'
};
export { Links };
+3 -1
View File
@@ -43,6 +43,7 @@
"dropbox": "Dropbox",
"gdrive": "Google Drive",
"onedrive": "OneDrive",
"msteams": "Microsoft Teams",
"menuAllItems": "All Items",
"menuColors": "Colors",
"menuTrash": "Trash",
@@ -432,7 +433,8 @@
"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 Autotype",
"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",
+79 -4
View File
@@ -14,6 +14,7 @@
"or": "ou",
"history": "historique",
"template": "modèle",
"templates": "templates",
"notImplemented": "Non Implémenté",
"saveChanges": "Sauvegarder les modifications",
"discardChanges": "Annuler les modifications",
@@ -46,6 +47,7 @@
"menuColors": "Couleurs",
"menuTrash": "Corbeille",
"menuSetGeneral": "Général",
"menuSetBrowser": "Navigateur",
"menuSetAbout": "À propos",
"menuSetDevices": "Appareils",
"menuAlertNoTags": "Aucun tag",
@@ -60,7 +62,7 @@
"sysMenuServices": "Services",
"sysMenuHide": "Cacher {}",
"sysMenuHideOthers": "Cacher autres",
"sysMenuUnhide": "Montrer tous",
"sysMenuUnhide": "Montrer tout",
"sysMenuQuit": "Quitter {}",
"sysMenuEdit": "Editer",
"sysMenuUndo": "Annuler",
@@ -80,6 +82,8 @@
"alertCopy": "Copier",
"alertClose": "Fermer",
"alertDoNotAsk": "Ne plus me le redemander",
"alertAllow": "Autoriser",
"alertDeny": "Refuser",
"appBeta": "ATTENTION: version beta, aperçu seulement",
"footerOpen": "Ouvrir/Nouveau",
"footerSyncError": "Erreur de synchronisation",
@@ -139,6 +143,7 @@
"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",
"keyEsc": "Esc",
"iconFavTitle": "Télécharger et utiliser le favicon du site web",
"iconSelCustom": "Sélectionner une icône personnalisée",
"listEmptyTitle": "Vide",
@@ -267,6 +272,7 @@
"detMore": "plus",
"detClickToAddField": "cliquez pour ajouter un nouveau champ",
"detMenuAddNewField": "Ajouter nouveau champ",
"detMenuAddNewWebsite": "Ajouter un autre site",
"detMenuShowEmpty": "Montrer les champs vides",
"detMenuHideEmpty": "Cacher les champs vides",
"detMenuAddField": "Ajouter {}",
@@ -340,6 +346,7 @@
"autoTypeSelectionHintOpt": "Entrez seulement le compte",
"autoTypeSelectionHintShift": "Autres champs",
"autoTypeSelectionOtp": "code à usage unique",
"autoTypeUnlockMessage": "Déverrouiller pour saisir automatiquement",
"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.",
@@ -614,6 +621,38 @@
"setPlTranslateLink": "traduire l'appli dans votre langue",
"setPlAutoUpdate": "Mise à jour automatique",
"setPlLoadGallery": "Charger le catalogue",
"setBrowserTitle": "Navigateur",
"setBrowserIntroDesktop": "KeeWeb peut entrer des mots de passe en utilisant la saisie automatique, cependant, une extension peut être un moyen plus pratique de le faire. KeeWeb prend en charge deux extensions de navigateur:",
"setBrowserIntroKeeWebConnect": "l'extension officielle KeeWeb est construite avec les fonctionnalités de KeeWeb, mais vous risquez de manquer certaines fonctionnalités avancées que l'on peut trouver dans l'autre extension.",
"setBrowserIntroKeePassXcBrowser": "cette extension a été développée pour KeePassXC, elle existe depuis un moment et est assez fiable. L'extension ne fait pas partie de KeeWeb et il peut y avoir des problèmes de compatibilité.",
"setBrowserIntroWeb": "Installez notre extension de navigateur pour remplir automatiquement les mots de passe de KeeWeb sur différentes pages. L'extension de navigateur se connectera à un onglet KeeWeb de votre navigateur pour récupérer les mots de passe. Cliquez ici pour télécharger l'extension:",
"setBrowserNotEnabled": "L'intégration du navigateur n'est pas activée, les extensions ne pourront pas se connecter à KeeWeb. Utilisez les cases à cocher ci-dessous pour l'activer:",
"setBrowserEnablePerBrowser": "Activer l'intégration dans le navigateur en cochant ci dessous:",
"setBrowserFocusIfLocked": "Ouvrir KeeWeb si le navigateur essaye de se connecter alors que aucun fichier n'est ouvert",
"setBrowserFocusIfEmpty": "Afficher la liste si aucune correspondance n'est trouvée avec l'URL",
"setBrowserOtherBrowsers": "Autres navigateurs",
"setBrowserExtensionFor": "pour {}",
"setBrowserExtensionNotSupported": "Non supporté",
"setBrowserExtensionHelp": "Comment installer ?",
"setBrowserExtensionInstall": "Installer l'application",
"setBrowserExtensionKPXCWarnHeader": "{} cessera de fonctionner",
"setBrowserExtensionKPXCWarnBody1": "Malheureusement, il n'est pas possible de connecter une extension à plusieurs applications. Si vous connectez l'extension à KeeWeb, nous remplacerons son association d'application, ce qui signifie que l'intégration avec {} cessera de fonctionner. Même si vous décochez cette case, l'association avec {} ne sera pas restaurée. Pour le faire fonctionner à nouveau, configurez l'intégration du navigateur dans les paramètres de {}.",
"setBrowserExtensionKPXCWarnBody2": "Configurer l'extension pour utiliser KeeWeb?",
"setBrowserSessions": "Sessions",
"setBrowserSessionsEmpty": "Aucune session connectée",
"setBrowserSessionsIntro": "Ces extensions sont connectées à KeeWeb",
"setBrowserSessionsActiveTooltip": "Session active",
"setBrowserSessionsActiveText": "Cette session est active. Elle peut échanger des données avec KeeWeb selon les permissions:",
"setBrowserSessionsInactiveTooltip": "session inactive",
"setBrowserSessionsInactiveText": "Cette session est inactive. L'extension est connectée à KeeWeb, cependant, elle n'a pas essayé d'échanger des données. Lorsque l'extension demande quelque chose, vous pourrez choisir ce que vous souhaitez partager.",
"setBrowserSessionsDeniedTooltip": "Accès interdit",
"setBrowserSessionsDeniedText": "Cette session est inactive. L'extension est connectée à KeeWeb mais vous avez refusé l'accès aux données.",
"setBrowserSessionsConnectedDate": "Connecté",
"setBrowserSessionsTerminate": "Clôturer la session",
"setBrowserSessionsAccessToFiles": "Autoriser l'accès aux fichiers",
"setBrowserSessionsNoFileAccess": "L'extension n'a accès à aucun fichier, elle ne pourra pas récupérer les mots de passe de KeeWeb.",
"setBrowserSessionsPasswordsRead": "Accès aux mot de passe",
"setBrowserSessionsPasswordsWritten": "Mots de passe enregistrés",
"setDevicesTitle": "Appareils",
"setDevicesEnableUsb": "Autoriser les interactions avec les appareils USB",
"setDevicesYubiKeyIntro": "Il est recommandé de lire {} avant d'utiliser une YubiKey.",
@@ -648,12 +687,12 @@
"setHelpProblems2": "ou {}",
"setHelpOpenIssue": "faire connaître le problème sur GitHub",
"setHelpContactLink": "contactez le développeur directement",
"setHelpAppInfo": "Information",
"setHelpAppInfo": "Informations",
"setHelpOtherPlatforms": "Autres plateformes",
"setHelpDesktopApps": "Applis Desktop",
"setHelpWebApp": "Appli web",
"setHelpUpdates": "Mises à jour",
"setHelpTwitter": "Appli twitter",
"setHelpTwitter": "Twitter",
"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)",
@@ -669,6 +708,8 @@
"dropboxLinkFull": "Tout Dropbox ou n'importe quel dossier",
"dropboxLinkCustom": "Votre appli Dropbox",
"gdriveSharedWithMe": "Partagé avec moi",
"gdriveSharedDrives": "Lecteurs partagés",
"gdriveTeamDrives": "Team drives",
"webdavSaveMethod": "Méthode de sauvegarde",
"webdavSaveMove": "Envoyer un fichier temporaire et le déplacer",
"webdavSavePut": "Écraser le fichier kdbx avec PUT",
@@ -697,5 +738,39 @@
"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 \"{}\""
"bioOpenAuthPrompt": "ouvrir \"{}\"",
"extensionErrorNoOpenFiles": "Aucun fichier ouvert",
"extensionErrorUserRejected": "La requête a été refusée",
"extensionErrorNoMatches": "Aucune correspondance",
"extensionErrorAlertDisplayed": "Impossible de poser une question maintenant car une autre boîte de dialogue est affichée, veuillez réessayer",
"extensionConnectHeader": "Échange de données avec l'extension",
"extensionConnectIntro": "Une extension de navigateur qui a pour nom {} essaie d'échanger des données avec KeeWeb.",
"extensionConnectUnknownActivity": "KeeWeb ne vérifie pas que l'application connectée est ce qu'elle prétend être. N'approuvez la demande que si vous en connaissez l'origine.",
"extensionConnectFiles": "Lors de cette session, autoriser l'accès à:",
"extensionConnectAllOtherFiles": "Tous les autres fichiers",
"extensionConnectAllFiles": "Tous les fichiers",
"extensionConnectAskGet": "Demandez avant d'envoyer les mots de passe à l'extension:",
"extensionConnectAskGetMultiple": "s'il y a plus d'une correspondance",
"extensionConnectAskGetAlways": "Toujours",
"extensionConnectAskSave": "Demandez avant d'enregistrer de nouveaux mots de passe dans KeeWeb:",
"extensionConnectAskSaveAlways": "Toujours",
"extensionConnectAskSaveAuto": "quand ce n'est pas possible de sauvegarder automatiquement",
"extensionConnectSettingsAreForSession": "Les paramètres que vous sélectionnez ici ne sont valides que pour la session en cours. Vous pouvez afficher et gérer les sessions dans les paramètres de KeeWeb.",
"extensionUnlockMessage": "Déverrouiller pour connecter l'extension du navigateur",
"extensionNewGroupHeader": "Nouveau groupe",
"extensionNewGroupBody": "{} essaye de créer un nouveau groupe. Autoriser cela?",
"extensionNewGroupPath": "Dossier du groupe",
"extensionNewGroupFile": "Ce groupe sera créé dans:",
"extensionSaveEntryHeader": "Sauvegarder mot de passe",
"extensionSaveEntryBody": "{} essaye de sauvegarder un mot de passe. Autoriser cela?",
"extensionSaveEntryAuto": "Sauvegarder les autres mots de passe automatiquement lors de cette session",
"extensionSaveEntryNewGroup": "nouveau groupe",
"extensionSelectPasswordFor": "Sélectionner un mot de passe pour {}",
"selectEntryHeader": "Sélectionner une entrée",
"selectEntryEnterHint": "Utiliser la ligne sélectionnée",
"selectEntryTypingHint": "Ecrire pour filtrer",
"selectEntryContains": "Contient le texte",
"selectEntrySubdomains": "Sous-domaines",
"selectEntryFieldHeader": "Sélectionnez un champ",
"selectEntryFieldTouch": "Appuyez sur le bouton de votre appareil pour générer un code à usage unique."
}
+1 -1
View File
@@ -697,7 +697,7 @@ class AppModel {
let needLoadKeyFile = false;
if (!params.keyFileData && fileInfo && fileInfo.keyFileName) {
params.keyFileName = fileInfo.keyFileName;
if (this.settings.rememberKeyFiles === 'data') {
if (this.settings.rememberKeyFiles === 'data' && fileInfo.keyFileHash) {
params.keyFileData = FileModel.createKeyFileWithHash(fileInfo.keyFileHash);
} else if (this.settings.rememberKeyFiles === 'path' && fileInfo.keyFilePath) {
params.keyFilePath = fileInfo.keyFilePath;
+2 -2
View File
@@ -677,10 +677,10 @@ class FileModel extends Model {
addCustomIcon(iconData) {
const uuid = kdbxweb.KdbxUuid.random();
this.db.meta.customIcons[uuid] = {
this.db.meta.customIcons.set(uuid.id, {
data: kdbxweb.ByteUtils.arrayToBuffer(kdbxweb.ByteUtils.base64ToBytes(iconData)),
lastModified: new Date()
};
});
return uuid.toString();
}
+13 -5
View File
@@ -221,22 +221,30 @@ class StorageOneDrive extends StorageBase {
_getOAuthConfig() {
let clientId = this.appSettings.onedriveClientId;
let clientSecret = this.appSettings.onedriveClientSecret;
let tenant = this.appSettings.onedriveTenantId;
if (!clientId) {
if (Features.isDesktop) {
({ id: clientId, secret: clientSecret } = OneDriveApps.Desktop);
({ id: clientId, secret: clientSecret, tenantId: tenant } = OneDriveApps.Desktop);
} else if (Features.isLocal) {
({ id: clientId, secret: clientSecret } = OneDriveApps.Local);
({ id: clientId, secret: clientSecret, tenantId: tenant } = OneDriveApps.Local);
} else {
({ id: clientId, secret: clientSecret } = OneDriveApps.Production);
({
id: clientId,
secret: clientSecret,
tenantId: tenant
} = OneDriveApps.Production);
}
}
tenant = tenant || 'common';
let scope = 'files.readwrite';
if (!this.appSettings.shortLivedStorageToken) {
scope += ' offline_access';
}
return {
url: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
tokenUrl: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
url: `https://login.microsoftonline.com/${tenant}/oauth2/v2.0/authorize`,
tokenUrl: `https://login.microsoftonline.com/${tenant}/oauth2/v2.0/token`,
scope,
clientId,
clientSecret,
+365
View File
@@ -0,0 +1,365 @@
import { StorageBase } from 'storage/storage-base';
import { MsTeamsApps } from 'const/cloud-storage-apps';
import { Features } from 'util/features';
// https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow
// https://graph.microsoft.com/v1.0/me/transitiveMemberOf/microsoft.graph.group?$count=true
// https://graph.microsoft.com/v1.0/groups?$filter=groupTypes/any(c:c+eq+'Unified')
// https://graph.microsoft.com/v1.0/groups?$filter=groupTypes/any(c:c+eq+'Unified')&$orderby=displayName
// https://graph.microsoft.com/v1.0/groups?$orderby=displayName
// /me/joinedTeams
// https://graph.microsoft.com/v1.0/groups/{group id}/drive/root/children
class StorageTeams extends StorageBase {
name = 'msteams';
enabled = true;
uipos = 50;
icon = 'user-friends';
_graphUrl = 'https://graph.microsoft.com/v1.0';
_groupsUrl = `${this._graphUrl}/me/joinedTeams`;
_baseUrl = `${this._graphUrl}/groups`;
getPathForName(fileName) {
return '/drive/root:/' + fileName + '.kdbx';
}
genUrlAddress(groupId, path) {
if (groupId) {
return this._baseUrl + '/' + groupId + (path ? '/' + path.replace(/^\/+/, '') : '');
} else {
return this._groupsUrl;
}
}
genUrl(path) {
if (!path) {
const groupId = null;
const dir = null;
const url = this.genUrlAddress(groupId, dir);
return [groupId, dir, url];
}
const parts = path.replace(/^\/+/, '').split('/');
if (parts.length === 0) {
const groupId = null;
const dir = null;
const url = this.genUrlAddress(groupId, dir);
return [groupId, dir, url];
} else if (parts.length === 1) {
const groupId = parts[0];
const dir = null;
const url = this.genUrlAddress(groupId, dir);
return [groupId, dir, url];
} else {
path = path.replace(/\/drive\/root\:/, '');
const groupId = parts[0];
const dir = ('/' + parts.slice(1).join('/')).replace(/^\/+/, '');
const url = this.genUrlAddress(groupId, dir);
return [groupId, dir, url];
}
}
load(path, opts, callback) {
this._oauthAuthorize((err) => {
if (err) {
return callback && callback(err);
}
this.logger.debug('Load', path);
const ts = this.logger.ts();
const urlParts = this.genUrl(path);
const groupId = urlParts[0];
path = urlParts[1];
const url = urlParts[2];
if (!groupId) {
const err = 'no group id defined';
return callback && callback(err);
}
this._xhr({
url,
responseType: 'json',
success: (response) => {
const downloadUrl = response['@microsoft.graph.downloadUrl'];
let rev = response.eTag;
if (!downloadUrl || !response.eTag) {
this.logger.debug(
'Load error',
path,
'no download url',
response,
this.logger.ts(ts)
);
return callback && callback('no download url');
}
this._xhr({
url: downloadUrl,
responseType: 'arraybuffer',
skipAuth: true,
success: (response, xhr) => {
rev = xhr.getResponseHeader('ETag') || rev;
this.logger.debug('Loaded', path, rev, this.logger.ts(ts));
return callback && callback(null, response, { rev });
},
error: (err) => {
this.logger.error('Load error', path, err, this.logger.ts(ts));
return callback && callback(err);
}
});
},
error: (err) => {
this.logger.error('Load error', path, err, this.logger.ts(ts));
return callback && callback(err);
}
});
});
}
stat(path, opts, callback) {
this._oauthAuthorize((err) => {
if (err) {
return callback && callback(err);
}
this.logger.debug('Stat', path);
const ts = this.logger.ts();
const urlParts = this.genUrl(path);
const groupId = urlParts[0];
path = urlParts[1];
const url = urlParts[2];
if (!groupId) {
const err = 'no group id defined';
return callback && callback(err);
}
this._xhr({
url,
responseType: 'json',
success: (response) => {
const rev = response.eTag;
if (!rev) {
this.logger.error('Stat error', path, 'no eTag', this.logger.ts(ts));
return callback && callback('no eTag');
}
this.logger.debug('Stated', path, rev, this.logger.ts(ts));
return callback && callback(null, { rev });
},
error: (err, xhr) => {
if (xhr.status === 404) {
this.logger.debug('Stated not found', path, this.logger.ts(ts));
return callback && callback({ notFound: true });
}
this.logger.error('Stat error', path, err, this.logger.ts(ts));
return callback && callback(err);
}
});
});
}
save(path, opts, data, callback, rev) {
this._oauthAuthorize((err) => {
if (err) {
return callback && callback(err);
}
this.logger.debug('Save', path, rev);
const ts = this.logger.ts();
const urlParts = this.genUrl(path);
const groupId = urlParts[0];
path = urlParts[1];
const url = urlParts[2] + ':/content';
if (!groupId) {
const err = 'no group id defined';
return callback && callback(err);
}
this._xhr({
url,
method: 'PUT',
responseType: 'json',
headers: rev ? { 'If-Match': rev } : null,
data,
statuses: [200, 201, 412],
success: (response, xhr) => {
rev = response.eTag;
if (!rev) {
this.logger.error('Save error', path, 'no eTag', this.logger.ts(ts));
return callback && callback('no eTag');
}
if (xhr.status === 412) {
this.logger.debug('Save conflict', path, rev, this.logger.ts(ts));
return callback && callback({ revConflict: true }, { rev });
}
this.logger.debug('Saved', path, rev, this.logger.ts(ts));
return callback && callback(null, { rev });
},
error: (err) => {
this.logger.error('Save error', path, err, this.logger.ts(ts));
return callback && callback(err);
}
});
});
}
list(dir, callback) {
this._oauthAuthorize((err) => {
if (err) {
return callback && callback(err);
}
this.logger.debug('List', dir);
const ts = this.logger.ts();
const urlParts = this.genUrl(dir);
const groupId = urlParts[0];
dir = urlParts[1];
const urlPath = groupId ? (dir ? ':/children' : '/drive/root/children') : '';
const url = urlParts[2] + urlPath;
const self = this;
self._groupId = groupId;
this._xhr({
url,
responseType: 'json',
success: (response) => {
if (!response || !response.value) {
this.logger.error('List error', this.logger.ts(ts), response);
return callback && callback('list error');
}
this.logger.debug('Listed', this.logger.ts(ts));
let fileList;
if (!self._groupId) {
fileList = response.value
.filter((f) => f.displayName)
.map((f) => ({
name: f.displayName,
path: '/' + f.id,
rev: f.id,
dir: true
}));
} else {
fileList = response.value
.filter((f) => f.name)
.map((f) => ({
name: f.name,
path: `/${self._groupId}${f.parentReference.path}/${f.name}`,
rev: f.eTag,
dir: !!f.folder
}));
}
return callback && callback(null, fileList);
},
error: (err) => {
this.logger.error('List error', this.logger.ts(ts), err);
return callback && callback(err);
}
});
});
}
remove(path, callback) {
this.logger.debug('Remove', path);
const ts = this.logger.ts();
const urlParts = this.genUrl(path);
const groupId = urlParts[0];
path = urlParts[1];
const url = urlParts[2];
if (!groupId) {
const err = 'no group id defined';
return callback && callback(err);
}
this._xhr({
url,
method: 'DELETE',
responseType: 'json',
statuses: [200, 204],
success: () => {
this.logger.debug('Removed', path, this.logger.ts(ts));
return callback && callback();
},
error: (err) => {
this.logger.error('Remove error', path, err, this.logger.ts(ts));
return callback && callback(err);
}
});
}
mkdir(path, callback) {
this._oauthAuthorize((err) => {
if (err) {
return callback && callback(err);
}
this.logger.debug('Make dir', path);
const ts = this.logger.ts();
const urlParts = this.genUrl(path);
const groupId = urlParts[0];
path = urlParts[1];
const url = urlParts[2] + '/drive/root/children';
if (!groupId) {
const err = 'no group id defined';
return callback && callback(err);
}
const data = JSON.stringify({ name: path.replace('/drive/root:/', ''), folder: {} });
this._xhr({
url,
method: 'POST',
responseType: 'json',
statuses: [200, 204],
data,
dataType: 'application/json',
success: () => {
this.logger.debug('Made dir', path, this.logger.ts(ts));
return callback && callback();
},
error: (err) => {
this.logger.error('Make dir error', path, err, this.logger.ts(ts));
return callback && callback(err);
}
});
});
}
logout(enabled) {
this._oauthRevokeToken();
}
_getOAuthConfig() {
let clientId = this.appSettings.msteamsClientId;
let clientSecret = this.appSettings.msteamsClientSecret;
let tenant = this.appSettings.msteamsTenantId;
if (!clientId) {
if (Features.isDesktop) {
({ id: clientId, secret: clientSecret, tenantId: tenant } = MsTeamsApps.Desktop);
} else if (Features.isLocal) {
({ id: clientId, secret: clientSecret, tenantId: tenant } = MsTeamsApps.Local);
} else {
({ id: clientId, secret: clientSecret, tenantId: tenant } = MsTeamsApps.Production);
}
}
tenant = tenant || 'common';
let scope = 'Sites.ReadWrite.All Team.ReadBasic.All';
if (!this.appSettings.shortLivedStorageToken) {
scope += ' offline_access';
}
return {
url: `https://login.microsoftonline.com/${tenant}/oauth2/v2.0/authorize`,
tokenUrl: `https://login.microsoftonline.com/${tenant}/oauth2/v2.0/token`,
scope,
clientId,
clientSecret,
pkce: true,
width: 600,
height: 500
};
}
}
export { StorageTeams };
+2
View File
@@ -5,6 +5,7 @@ import { StorageFile } from 'storage/impl/storage-file';
import { StorageFileCache } from 'storage/impl/storage-file-cache';
import { StorageGDrive } from 'storage/impl/storage-gdrive';
import { StorageOneDrive } from 'storage/impl/storage-onedrive';
import { StorageTeams } from 'storage/impl/storage-teams';
import { StorageWebDav } from 'storage/impl/storage-webdav';
import { createOAuthSession } from 'storage/pkce';
@@ -17,6 +18,7 @@ const ThirdPartyStorage = {
dropbox: new StorageDropbox(),
gdrive: new StorageGDrive(),
onedrive: new StorageOneDrive(),
msteams: new StorageTeams(),
webdav: new StorageWebDav()
};
@@ -6,8 +6,8 @@ const ExpectedFieldRefByteLength = ExpectedFieldRefChars.length;
kdbxweb.ProtectedValue.prototype.isProtected = true;
kdbxweb.ProtectedValue.prototype.forEachChar = function (fn) {
const value = this._value;
const salt = this._salt;
const value = this.value;
const salt = this.salt;
let b, b1, b2, b3;
for (let i = 0, len = value.length; i < len; i++) {
b = value[i] ^ salt[i];
@@ -154,7 +154,7 @@ kdbxweb.ProtectedValue.prototype.equals = function (other) {
return false;
}
for (let i = 0; i < len; i++) {
if ((this._value[i] ^ this._salt[i]) !== (other._value[i] ^ other._salt[i])) {
if ((this.value[i] ^ this.salt[i]) !== (other.value[i] ^ other.salt[i])) {
return false;
}
}
@@ -181,8 +181,8 @@ kdbxweb.ProtectedValue.prototype.saltedValue = function () {
if (!this.byteLength) {
return 0;
}
const value = this._value;
const salt = this._salt;
const value = this.value;
const salt = this.salt;
let salted = '';
for (let i = 0, len = value.length; i < len; i++) {
const byte = value[i] ^ salt[i];
@@ -193,8 +193,8 @@ kdbxweb.ProtectedValue.prototype.saltedValue = function () {
kdbxweb.ProtectedValue.prototype.dataAndSalt = function () {
return {
data: [...this._value],
salt: [...this._salt]
data: [...this.value],
salt: [...this.salt]
};
};
@@ -57,7 +57,7 @@ class SettingsBrowserView extends View {
} else {
const extensionBrowserFamily = Features.extensionBrowserFamily;
data.extensionBrowserFamily = Features.extensionBrowserFamily;
data.extensionDownloadLink = Links[`KeeWebConnectFor${extensionBrowserFamily}`];
data.extensionDownloadLink = Links[`KWCFor${extensionBrowserFamily}`];
}
super.render(data);
}
@@ -72,6 +72,9 @@ class SettingsBrowserView extends View {
enabled: !!AppSettingsModel[`extensionEnabled${ext.alias}${browser}`],
installUrl: Links[`${ext.alias}For${browser}`]
};
if (ext.alias === 'KPXC') {
ext.manualUrl = Links.ExtensionHelpForKPXC;
}
if (!ext.installUrl) {
if (browser === 'Other') {
ext.helpUrl = Links.ExtensionHelpForOtherBrowsers;
@@ -53,6 +53,7 @@ class SettingsGeneralView extends View {
'change .settings__general-use-markdown': 'changeUseMarkdown',
'change .settings__general-use-group-icon-for-entries': 'changeUseGroupIconForEntries',
'change .settings__general-direct-autotype': 'changeDirectAutotype',
'change .settings__general-autotype-title-filter': 'changeAutoTypeTitleFilter',
'change .settings__general-field-label-dblclick-autotype':
'changeFieldLabelDblClickAutoType',
'change .settings__general-device-owner-auth': 'changeDeviceOwnerAuth',
@@ -135,6 +136,7 @@ class SettingsGeneralView extends View {
useMarkdown: AppSettingsModel.useMarkdown,
useGroupIconForEntries: AppSettingsModel.useGroupIconForEntries,
directAutotype: AppSettingsModel.directAutotype,
autoTypeTitleFilterEnabled: AppSettingsModel.autoTypeTitleFilterEnabled,
fieldLabelDblClickAutoType: AppSettingsModel.fieldLabelDblClickAutoType,
supportsTitleBarStyles: Features.supportsTitleBarStyles,
supportsCustomTitleBarAndDraggableWindow:
@@ -431,6 +433,11 @@ class SettingsGeneralView extends View {
AppSettingsModel.directAutotype = directAutotype;
}
changeAutoTypeTitleFilter(e) {
const autoTypeTitleFilterEnabled = e.target.checked || false;
AppSettingsModel.autoTypeTitleFilterEnabled = autoTypeTitleFilterEnabled;
}
changeFieldLabelDblClickAutoType(e) {
const fieldLabelDblClickAutoType = e.target.checked || false;
AppSettingsModel.fieldLabelDblClickAutoType = fieldLabelDblClickAutoType;
+1
View File
@@ -78,6 +78,7 @@
&__table {
flex: 1;
width: 100%;
height: 0;
overflow: hidden;
border-collapse: collapse;
table-layout: fixed;
+8 -1
View File
@@ -334,8 +334,11 @@
}
}
&__donate-btn {
$donate-border-color: #89abed;
background: #fff;
border: 2px solid #89abed;
border: 2px solid $donate-border-color;
border-bottom: 2px solid $donate-border-color;
border-radius: 2.8rem;
text-align: center;
display: inline-block;
@@ -345,6 +348,10 @@
height: 2.8rem;
margin-bottom: $base-padding-v * 2;
&:hover {
border-bottom: 2px solid $donate-border-color;
}
&-top,
&-bottom {
pointer-events: none;
+1
View File
@@ -82,6 +82,7 @@ $fa-var-file-image: next-fa-glyph();
$fa-var-file-video: next-fa-glyph();
$fa-var-file-audio: next-fa-glyph();
$fa-var-onedrive: next-fa-glyph();
$fa-var-user-friends: next-fa-glyph();
$fa-var-question: next-fa-glyph();
$fa-var-sign-out-alt: next-fa-glyph();
$fa-var-sync-alt: next-fa-glyph();
+1 -1
View File
@@ -3,7 +3,7 @@
<p>{{#res 'setAboutFirst'}}<a href="https://antelle.net" target="_blank">Antelle</a>{{/res~}}&nbsp;
{{~#res 'setAboutSecond'}}<a href="{{licenseLink}}" target="_blank">MIT</a>{{/res}}
{{#res 'setAboutSource'}}<a href="{{repoLink}}" target="_blank">GitHub <i class="fa fa-github-alt bottom"></i></a>{{/res}}</p>
<a href="{{donationLink}}" target="_blank" class="settings__donate-btn no-border">
<a href="{{donationLink}}" target="_blank" class="settings__donate-btn">
<span class="settings__donate-btn-top">Become a</span><span class="settings__donate-btn-bottom">Backer</span>
</a>
<p>{{res 'setAboutBuilt'}}:</p>
+34 -25
View File
@@ -24,33 +24,42 @@
<td>{{perBrowser.browserName}}</td>
{{#each perBrowser.extensions as |setting|}}
<td>
{{#if setting.supported}}
<input type="checkbox"
class="check-enable-for-browser"
{{#if setting.enabled}}checked{{/if}}
id="check-enable-{{setting.alias}}-for-{{perBrowser.browser}}"
data-browser="{{perBrowser.browser}}"
data-extension="{{setting.alias}}" />
<label for="check-enable-{{setting.alias}}-for-{{perBrowser.browser}}"></label>
{{#if setting.manualUrl}}
<a href="{{setting.manualUrl}}" target="_blank" rel="noreferrer"
class="settings__browser-extension-link icon-link"
title="{{res 'setBrowserExtensionHelp'}}"
>
<i class="fa fa-info-circle"></i>
</a>
{{else}}
<i class="fa fa-times muted-color" title="{{res 'setBrowserExtensionNotSupported'}}"></i>
{{/if}}
{{#if setting.enabled}}
{{#if setting.helpUrl}}
<a href="{{setting.helpUrl}}" target="_blank" rel="noreferrer"
class="settings__browser-extension-link icon-link"
title="{{res 'setBrowserExtensionHelp'}}"
>
<i class="fa fa-info-circle"></i>
</a>
{{#if setting.supported}}
<input type="checkbox"
class="check-enable-for-browser"
{{#if setting.enabled}}checked{{/if}}
id="check-enable-{{setting.alias}}-for-{{perBrowser.browser}}"
data-browser="{{perBrowser.browser}}"
data-extension="{{setting.alias}}" />
<label for="check-enable-{{setting.alias}}-for-{{perBrowser.browser}}"></label>
{{else}}
<i class="fa fa-times muted-color" title="{{res 'setBrowserExtensionNotSupported'}}"></i>
{{/if}}
{{#if setting.installUrl}}
<a href="{{setting.installUrl}}" target="_blank" rel="noreferrer"
class="settings__browser-extension-link icon-link"
title="{{res 'setBrowserExtensionInstall'}}"
>
<i class="fa fa-download"></i>
</a>
{{#if setting.enabled}}
{{#if setting.helpUrl}}
<a href="{{setting.helpUrl}}" target="_blank" rel="noreferrer"
class="settings__browser-extension-link icon-link"
title="{{res 'setBrowserExtensionHelp'}}"
>
<i class="fa fa-info-circle"></i>
</a>
{{/if}}
{{#if setting.installUrl}}
<a href="{{setting.installUrl}}" target="_blank" rel="noreferrer"
class="settings__browser-extension-link icon-link"
title="{{res 'setBrowserExtensionInstall'}}"
>
<i class="fa fa-download"></i>
</a>
{{/if}}
{{/if}}
{{/if}}
</td>
@@ -169,6 +169,11 @@
id="settings__general-direct-autotype" {{#if directAutotype}}checked{{/if}} />
<label for="settings__general-direct-autotype">{{res 'setGenDirectAutotype'}}</label>
</div>
<div>
<input type="checkbox" class="settings__input input-base settings__general-autotype-title-filter"
id="settings__general-autotype-title-filter" {{#if autoTypeTitleFilterEnabled}}checked{{/if}} />
<label for="settings__general-autotype-title-filter">{{res 'setGenAutoTypeTitleFilterEnabled'}}</label>
</div>
<div>
<input type="checkbox" class="settings__input input-base settings__general-field-label-dblclick-autotype"
id="settings__general-field-label-dblclick-autotype" {{#if fieldLabelDblClickAutoType}}checked{{/if}} />
+36 -12
View File
@@ -97,7 +97,11 @@ const settingsPromise = loadSettingsEncryptionKey().then((key) => {
logProgress('loading settings key');
return loadConfig('app-settings').then((settings) => {
appSettings = settings ? JSON.parse(settings) : {};
try {
appSettings = settings ? JSON.parse(settings) : {};
} catch (e) {
logStartupMessage(`Error loading app settings: ${e}`);
}
logProgress('reading app settings');
});
});
@@ -198,7 +202,9 @@ main.minimizeApp = function (menuItemLabels) {
if (!appIcon) {
const image = electron.nativeImage.createFromPath(path.join(__dirname, 'img', imagePath));
appIcon = new electron.Tray(image);
appIcon.on('click', restoreMainWindow);
if (process.platform !== 'darwin') {
appIcon.on('click', restoreMainWindow);
}
const contextMenu = electron.Menu.buildFromTemplate([
{ label: menuItemLabels.restore, click: restoreMainWindow },
{ label: menuItemLabels.quit, click: closeMainWindow }
@@ -372,6 +378,9 @@ function restoreMainWindow() {
}
function showAndFocusMainWindow() {
if (appIcon) {
restoreMainWindow();
}
if (mainWindowMaximized) {
mainWindow.maximize();
} else {
@@ -444,7 +453,11 @@ function restoreMainWindowPosition() {
const fileName = path.join(main.getPath('userData'), windowPositionFileName);
fs.readFile(fileName, 'utf8', (e, data) => {
if (data) {
mainWindowPosition = JSON.parse(data);
try {
mainWindowPosition = JSON.parse(data);
} catch (e) {
logStartupMessage(`Error loading main window position: ${e}`);
}
if (mainWindow && mainWindowPosition) {
if (mainWindowPosition.width && mainWindowPosition.height) {
mainWindow.setBounds(mainWindowPosition);
@@ -650,7 +663,9 @@ function setUserDataPaths() {
}
if (isDev && process.env.KEEWEB_IS_PORTABLE) {
isPortable = !!JSON.parse(process.env.KEEWEB_IS_PORTABLE);
try {
isPortable = !!JSON.parse(process.env.KEEWEB_IS_PORTABLE);
} catch {}
}
logProgress('portable check');
@@ -660,15 +675,22 @@ function setUserDataPaths() {
const portableConfigPath = path.join(portableConfigDir, portableConfigFileName);
if (fs.existsSync(portableConfigPath)) {
const portableConfig = JSON.parse(fs.readFileSync(portableConfigPath, 'utf8'));
const portableUserDataDir = path.resolve(portableConfigDir, portableConfig.userDataDir);
try {
const portableConfig = JSON.parse(fs.readFileSync(portableConfigPath, 'utf8'));
const portableUserDataDir = path.resolve(
portableConfigDir,
portableConfig.userDataDir
);
if (!fs.existsSync(portableUserDataDir)) {
fs.mkdirSync(portableUserDataDir, { recursive: true });
if (!fs.existsSync(portableUserDataDir)) {
fs.mkdirSync(portableUserDataDir, { recursive: true });
}
main.setPath('userData', portableUserDataDir);
usingPortableUserDataDir = true;
} catch (e) {
logStartupMessage(`Error loading portable config: ${e}`);
}
main.setPath('userData', portableUserDataDir);
usingPortableUserDataDir = true;
}
}
@@ -914,7 +936,9 @@ function loadLocale() {
if (appSettings?.locale === localeValues?.locale) {
setLocale(localeValues);
}
} catch {}
} catch (e) {
logStartupMessage(`Error loading locale: ${e}`);
}
}
locale.on('changed', () => {
setMenu();
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "KeeWeb",
"version": "1.18.1",
"version": "1.18.7",
"description": "Free cross-platform password manager compatible with KeePass",
"main": "main.js",
"homepage": "https://keeweb.info",
@@ -306,24 +306,29 @@ async function processFirstMessageFromSocket(socket, message) {
let parentProcessInfo;
try {
parentProcessInfo = await getProcessInfo(message.ppid);
} catch (e) {
logger.error(`Cannot get info for PID ${message.ppid}: ${e}`);
socket.destroy();
return;
}
if (process.platform === 'win32' && parentProcessInfo.appName === 'cmd') {
try {
parentProcessInfo = await getProcessInfo(parentProcessInfo.ppid);
parentProcessInfo = await getProcessInfo(message.ppid);
} catch (e) {
logger.error(
`Cannot get info for PID ${parentProcessInfo.ppid}: ${e}, assuming cmd is the launcher`
);
logger.error(`Cannot get info for PID ${message.ppid}: ${e}`);
throw e;
}
if (process.platform === 'win32' && parentProcessInfo.appName === 'cmd') {
try {
parentProcessInfo = await getProcessInfo(parentProcessInfo.ppid);
} catch (e) {
logger.error(
`Cannot get info for PID ${parentProcessInfo.ppid}: ${e}, assuming cmd is the launcher`
);
}
}
} catch (e) {
logger.warn('Cannot get process info, assuming the connection is not identified');
}
appName = AppNames[parentProcessInfo.appName] ?? parentProcessInfo.appName;
appName = parentProcessInfo
? AppNames[parentProcessInfo.appName] ?? parentProcessInfo.appName
: 'Unidentified browser';
appName = appName[0].toUpperCase() + appName.substr(1);
}
@@ -393,7 +398,11 @@ function sendMessageToSocket(socket, message) {
const lengthBytes = Buffer.from(lengthBuf);
const data = Buffer.concat([lengthBytes, responseData]);
socket.write(data);
try {
socket.write(data);
} catch (e) {
logger.error(`Error writing to socket ${state.socketId}`, e);
}
}
function sendToRenderer(event, socketId, data) {
+2 -2
View File
@@ -39,7 +39,7 @@ function installDarwinUpdate(updateFilePath) {
`--app=${appPath}`
]);
electron.app.exit(0);
electron.app.quit();
}
function installWin32Update(updateFilePath) {
@@ -52,7 +52,7 @@ function installWin32Update(updateFilePath) {
const ps = spawnDetached('cmd');
ps.stdin.end(`${updateCommand}\nexit\n`, 'utf8', () => {
electron.app.exit(0);
electron.app.quit();
});
}
+15 -15
View File
@@ -1,11 +1,11 @@
{
"name": "keeweb",
"version": "1.18.1",
"version": "1.18.7",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"version": "1.17.6",
"version": "1.18.5",
"license": "MIT",
"dependencies": {
"@babel/core": "^7.14.0",
@@ -14,7 +14,7 @@
"@babel/plugin-proposal-optional-chaining": "^7.13.12",
"@babel/preset-env": "^7.14.1",
"@fortawesome/fontawesome-free": "^5.15.3",
"@keeweb/keeweb-native-messaging-host": "https://github.com/keeweb/keeweb-connect/releases/download/0.3.3/keeweb-native-messaging-host.tgz",
"@keeweb/keeweb-native-messaging-host": "https://github.com/keeweb/keeweb-connect/releases/download/0.3.5/keeweb-native-messaging-host.tgz",
"@keeweb/keeweb-native-modules": "https://github.com/keeweb/keeweb-native-modules/releases/download/0.11.6/keeweb-native-modules.tgz",
"adm-zip": "^0.5.5",
"argon2-browser": "1.15.4",
@@ -67,7 +67,7 @@
"jquery": "3.6.0",
"json-loader": "^0.5.7",
"jsqrcode": "github:antelle/jsqrcode#0.1.3",
"kdbxweb": "^2.0.0",
"kdbxweb": "^2.0.4",
"load-grunt-tasks": "5.1.0",
"lodash": "^4.17.21",
"marked": "^2.0.3",
@@ -1567,9 +1567,9 @@
}
},
"node_modules/@keeweb/keeweb-native-messaging-host": {
"version": "0.3.3",
"resolved": "https://github.com/keeweb/keeweb-connect/releases/download/0.3.3/keeweb-native-messaging-host.tgz",
"integrity": "sha512-AvHWU0Bwv46Xl6PLyehRRNuZMn+3iWB9zf/YORp4JoJQhQuO8E3XODUadz2gMrZ/irHxC71sQlZG1vAOiUJqdw==",
"version": "0.3.5",
"resolved": "https://github.com/keeweb/keeweb-connect/releases/download/0.3.5/keeweb-native-messaging-host.tgz",
"integrity": "sha512-LitShO2m12x9z/FyNzLpmsA90bz96a45uESyz6oAQvoIqW7axrHtNqb8KHvmY8oz9+CySD3It8y+XuLXXS+gfw==",
"license": "MIT"
},
"node_modules/@keeweb/keeweb-native-modules": {
@@ -11706,9 +11706,9 @@
}
},
"node_modules/kdbxweb": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/kdbxweb/-/kdbxweb-2.0.0.tgz",
"integrity": "sha512-oomAWfJRkgWU+1Bi20N2SXJbHLT2wnCibIsdXQm5HNQ8ot2wRa6weAMxvfekYWKbo3/mLKwLV8mq4cNhjXwhTw==",
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/kdbxweb/-/kdbxweb-2.0.4.tgz",
"integrity": "sha512-Ckb3shx9E+VX6WZSvT6kJJknTA10T21M4HP8Z/xanZ65mwyQf7Mv0UreK/NUsa9BaejWEiB/QJxkTzrQZRn9Lg==",
"dependencies": {
"pako": "github:keeweb/pako#653c0b00d8941c89d09ed4546d2179001ec44efc",
"xmldom": "github:keeweb/xmldom#ec8f61f723e2f403adaf7a1bbf55ced4ff1ea0c6"
@@ -21888,8 +21888,8 @@
}
},
"@keeweb/keeweb-native-messaging-host": {
"version": "https://github.com/keeweb/keeweb-connect/releases/download/0.3.3/keeweb-native-messaging-host.tgz",
"integrity": "sha512-AvHWU0Bwv46Xl6PLyehRRNuZMn+3iWB9zf/YORp4JoJQhQuO8E3XODUadz2gMrZ/irHxC71sQlZG1vAOiUJqdw=="
"version": "https://github.com/keeweb/keeweb-connect/releases/download/0.3.5/keeweb-native-messaging-host.tgz",
"integrity": "sha512-LitShO2m12x9z/FyNzLpmsA90bz96a45uESyz6oAQvoIqW7axrHtNqb8KHvmY8oz9+CySD3It8y+XuLXXS+gfw=="
},
"@keeweb/keeweb-native-modules": {
"version": "https://github.com/keeweb/keeweb-native-modules/releases/download/0.11.6/keeweb-native-modules.tgz",
@@ -29846,9 +29846,9 @@
}
},
"kdbxweb": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/kdbxweb/-/kdbxweb-2.0.0.tgz",
"integrity": "sha512-oomAWfJRkgWU+1Bi20N2SXJbHLT2wnCibIsdXQm5HNQ8ot2wRa6weAMxvfekYWKbo3/mLKwLV8mq4cNhjXwhTw==",
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/kdbxweb/-/kdbxweb-2.0.4.tgz",
"integrity": "sha512-Ckb3shx9E+VX6WZSvT6kJJknTA10T21M4HP8Z/xanZ65mwyQf7Mv0UreK/NUsa9BaejWEiB/QJxkTzrQZRn9Lg==",
"requires": {
"pako": "github:keeweb/pako#653c0b00d8941c89d09ed4546d2179001ec44efc",
"xmldom": "github:keeweb/xmldom#ec8f61f723e2f403adaf7a1bbf55ced4ff1ea0c6"
+4 -4
View File
@@ -1,6 +1,6 @@
{
"name": "keeweb",
"version": "1.18.1",
"version": "1.18.7",
"description": "Free cross-platform password manager compatible with KeePass",
"main": "Gruntfile.js",
"private": true,
@@ -16,7 +16,7 @@
"@babel/plugin-proposal-optional-chaining": "^7.13.12",
"@babel/preset-env": "^7.14.1",
"@fortawesome/fontawesome-free": "^5.15.3",
"@keeweb/keeweb-native-messaging-host": "https://github.com/keeweb/keeweb-connect/releases/download/0.3.3/keeweb-native-messaging-host.tgz",
"@keeweb/keeweb-native-messaging-host": "https://github.com/keeweb/keeweb-connect/releases/download/0.3.5/keeweb-native-messaging-host.tgz",
"@keeweb/keeweb-native-modules": "https://github.com/keeweb/keeweb-native-modules/releases/download/0.11.6/keeweb-native-modules.tgz",
"adm-zip": "^0.5.5",
"argon2-browser": "1.15.4",
@@ -69,7 +69,7 @@
"jquery": "3.6.0",
"json-loader": "^0.5.7",
"jsqrcode": "github:antelle/jsqrcode#0.1.3",
"kdbxweb": "^2.0.0",
"kdbxweb": "^2.0.4",
"load-grunt-tasks": "5.1.0",
"lodash": "^4.17.21",
"marked": "^2.0.3",
@@ -123,7 +123,7 @@
"author": {
"name": "Antelle",
"email": "antelle.net@gmail.com",
"url": "http://antelle.net"
"url": "https://antelle.net"
},
"engines": {
"node": ">=10.0"
+31
View File
@@ -1,5 +1,36 @@
Release notes
-------------
##### v1.18.7 (2021-07-18)
`+` added Microsoft Teams storage
`+` added a possibility to override tenant in Microsoft OneDrive
`!` disabled automatic installation of KeePassXC-Browser extension
`+` added an option to diagnose YubiKey code listing issues
`-` fix #1845: fixed a visible crash on socket write error
##### v1.18.6 (2021-05-19)
`-` fix #1824: saving KDBX3 files with compression disabled
`-` fix #1818: extension connection error if browser cannot be identified
`-` fix #1820: minimize on close on macOS
##### v1.18.5 (2021-05-14)
`-` fix #1816: old Chromium support, such as Android Edge
`-` fix #1817: crash on files with large attachments as KDBX3
##### v1.18.4 (2021-05-12)
`+` #1814: option to disable auto-type title filter by default
`-` #1808: restore KeeWeb from system tray on extension request
`-` fix #1810: extension connection on old macOS (10.11)
`-` fix #1813: custom icon selection
`-` fix #1811: app doesn't quit during update
##### v1.18.3 (2021-05-09)
`-` fix #1804: filling OTP in browser extensions
`*` fix #1805: auto-unchecking auto-type filters if nothing found
`*` fix #1806: fixed a possible config loading error during startup
##### v1.18.2 (2021-05-08)
`-` fix #1802: opening files with saved keyfiles
##### v1.18.1 (2021-05-08)
`-` fixed entry attachments display