From 76fdd9864ced88bee89580bd95d3b46b3165f7bd Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Sat, 16 Jan 2021 15:13:58 +0100 Subject: [PATCH 1/9] Fixed copyright header --- src/activity_manager.rs | 2 +- src/bookmarks/mod.rs | 2 +- src/bookmarks/serializer.rs | 2 +- src/config/mod.rs | 2 +- src/config/serializer.rs | 2 +- src/filetransfer/ftp_transfer.rs | 2 +- src/filetransfer/mod.rs | 2 +- src/filetransfer/scp_transfer.rs | 2 +- src/filetransfer/sftp_transfer.rs | 2 +- src/fs/explorer/builder.rs | 2 +- src/fs/explorer/mod.rs | 2 +- src/fs/mod.rs | 2 +- src/host/mod.rs | 2 +- src/lib.rs | 2 +- src/main.rs | 2 +- src/system/bookmarks_client.rs | 2 +- src/system/config_client.rs | 2 +- src/system/environment.rs | 2 +- src/system/mod.rs | 2 +- src/system/sshkey_storage.rs | 2 +- src/ui/activities/auth_activity/bookmarks.rs | 2 +- src/ui/activities/auth_activity/callbacks.rs | 2 +- src/ui/activities/auth_activity/input.rs | 2 +- src/ui/activities/auth_activity/layout.rs | 2 +- src/ui/activities/auth_activity/mod.rs | 2 +- src/ui/activities/filetransfer_activity/callbacks.rs | 2 +- src/ui/activities/filetransfer_activity/input.rs | 2 +- src/ui/activities/filetransfer_activity/layout.rs | 2 +- src/ui/activities/filetransfer_activity/misc.rs | 2 +- src/ui/activities/filetransfer_activity/mod.rs | 2 +- src/ui/activities/filetransfer_activity/session.rs | 2 +- src/ui/activities/mod.rs | 2 +- src/ui/activities/setup_activity/callbacks.rs | 2 +- src/ui/activities/setup_activity/config.rs | 2 +- src/ui/activities/setup_activity/input.rs | 2 +- src/ui/activities/setup_activity/layout.rs | 2 +- src/ui/activities/setup_activity/misc.rs | 2 +- src/ui/activities/setup_activity/mod.rs | 2 +- src/ui/context.rs | 2 +- src/ui/input.rs | 2 +- src/ui/mod.rs | 2 +- src/utils/crypto.rs | 2 +- src/utils/fmt.rs | 2 +- src/utils/mod.rs | 2 +- src/utils/parser.rs | 2 +- src/utils/random.rs | 2 +- 46 files changed, 46 insertions(+), 46 deletions(-) diff --git a/src/activity_manager.rs b/src/activity_manager.rs index d36b4c9..b8964a0 100644 --- a/src/activity_manager.rs +++ b/src/activity_manager.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/bookmarks/mod.rs b/src/bookmarks/mod.rs index 331d412..6171916 100644 --- a/src/bookmarks/mod.rs +++ b/src/bookmarks/mod.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/bookmarks/serializer.rs b/src/bookmarks/serializer.rs index 4835f26..5204b2e 100644 --- a/src/bookmarks/serializer.rs +++ b/src/bookmarks/serializer.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/config/mod.rs b/src/config/mod.rs index 6178a51..05f23a8 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/config/serializer.rs b/src/config/serializer.rs index e2d62a3..89334d1 100644 --- a/src/config/serializer.rs +++ b/src/config/serializer.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/filetransfer/ftp_transfer.rs b/src/filetransfer/ftp_transfer.rs index 7fa03b5..bee6440 100644 --- a/src/filetransfer/ftp_transfer.rs +++ b/src/filetransfer/ftp_transfer.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/filetransfer/mod.rs b/src/filetransfer/mod.rs index 92d5af5..3a561f4 100644 --- a/src/filetransfer/mod.rs +++ b/src/filetransfer/mod.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/filetransfer/scp_transfer.rs b/src/filetransfer/scp_transfer.rs index 13f1a43..0b8cafa 100644 --- a/src/filetransfer/scp_transfer.rs +++ b/src/filetransfer/scp_transfer.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/filetransfer/sftp_transfer.rs b/src/filetransfer/sftp_transfer.rs index 38e1edb..c7ce56d 100644 --- a/src/filetransfer/sftp_transfer.rs +++ b/src/filetransfer/sftp_transfer.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/fs/explorer/builder.rs b/src/fs/explorer/builder.rs index 2e16dcc..41ba028 100644 --- a/src/fs/explorer/builder.rs +++ b/src/fs/explorer/builder.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/fs/explorer/mod.rs b/src/fs/explorer/mod.rs index 73011e0..6cc41cf 100644 --- a/src/fs/explorer/mod.rs +++ b/src/fs/explorer/mod.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/fs/mod.rs b/src/fs/mod.rs index ea718a9..96f14e8 100644 --- a/src/fs/mod.rs +++ b/src/fs/mod.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/host/mod.rs b/src/host/mod.rs index 2411991..9aec7c1 100644 --- a/src/host/mod.rs +++ b/src/host/mod.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/lib.rs b/src/lib.rs index d65280e..280e257 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/main.rs b/src/main.rs index f7f8a9b..52de229 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/system/bookmarks_client.rs b/src/system/bookmarks_client.rs index e071dbc..3c9510f 100644 --- a/src/system/bookmarks_client.rs +++ b/src/system/bookmarks_client.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/system/config_client.rs b/src/system/config_client.rs index 16d034a..50a1061 100644 --- a/src/system/config_client.rs +++ b/src/system/config_client.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/system/environment.rs b/src/system/environment.rs index 29798b3..0b994ae 100644 --- a/src/system/environment.rs +++ b/src/system/environment.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/system/mod.rs b/src/system/mod.rs index b31a84c..2e2e624 100644 --- a/src/system/mod.rs +++ b/src/system/mod.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/system/sshkey_storage.rs b/src/system/sshkey_storage.rs index 20eb8b2..cab222e 100644 --- a/src/system/sshkey_storage.rs +++ b/src/system/sshkey_storage.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/auth_activity/bookmarks.rs b/src/ui/activities/auth_activity/bookmarks.rs index f035b9d..f9f553d 100644 --- a/src/ui/activities/auth_activity/bookmarks.rs +++ b/src/ui/activities/auth_activity/bookmarks.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/auth_activity/callbacks.rs b/src/ui/activities/auth_activity/callbacks.rs index 645f6ca..db4bf1e 100644 --- a/src/ui/activities/auth_activity/callbacks.rs +++ b/src/ui/activities/auth_activity/callbacks.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/auth_activity/input.rs b/src/ui/activities/auth_activity/input.rs index 6f9fb33..e939503 100644 --- a/src/ui/activities/auth_activity/input.rs +++ b/src/ui/activities/auth_activity/input.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/auth_activity/layout.rs b/src/ui/activities/auth_activity/layout.rs index 7368bc3..a779aa1 100644 --- a/src/ui/activities/auth_activity/layout.rs +++ b/src/ui/activities/auth_activity/layout.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/auth_activity/mod.rs b/src/ui/activities/auth_activity/mod.rs index f1fa96c..95de2b9 100644 --- a/src/ui/activities/auth_activity/mod.rs +++ b/src/ui/activities/auth_activity/mod.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/filetransfer_activity/callbacks.rs b/src/ui/activities/filetransfer_activity/callbacks.rs index 702082c..7dbf8e6 100644 --- a/src/ui/activities/filetransfer_activity/callbacks.rs +++ b/src/ui/activities/filetransfer_activity/callbacks.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/filetransfer_activity/input.rs b/src/ui/activities/filetransfer_activity/input.rs index 23ecc83..8abc8fc 100644 --- a/src/ui/activities/filetransfer_activity/input.rs +++ b/src/ui/activities/filetransfer_activity/input.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/filetransfer_activity/layout.rs b/src/ui/activities/filetransfer_activity/layout.rs index 4cf3600..641a2f6 100644 --- a/src/ui/activities/filetransfer_activity/layout.rs +++ b/src/ui/activities/filetransfer_activity/layout.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/filetransfer_activity/misc.rs b/src/ui/activities/filetransfer_activity/misc.rs index 3c0c286..e9cb9dd 100644 --- a/src/ui/activities/filetransfer_activity/misc.rs +++ b/src/ui/activities/filetransfer_activity/misc.rs @@ -1,6 +1,6 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/filetransfer_activity/mod.rs b/src/ui/activities/filetransfer_activity/mod.rs index e6b9aeb..e011bb3 100644 --- a/src/ui/activities/filetransfer_activity/mod.rs +++ b/src/ui/activities/filetransfer_activity/mod.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/filetransfer_activity/session.rs b/src/ui/activities/filetransfer_activity/session.rs index 9ef9660..ad702a1 100644 --- a/src/ui/activities/filetransfer_activity/session.rs +++ b/src/ui/activities/filetransfer_activity/session.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/mod.rs b/src/ui/activities/mod.rs index dc188ab..70bf591 100644 --- a/src/ui/activities/mod.rs +++ b/src/ui/activities/mod.rs @@ -5,7 +5,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/setup_activity/callbacks.rs b/src/ui/activities/setup_activity/callbacks.rs index 98205ce..9074124 100644 --- a/src/ui/activities/setup_activity/callbacks.rs +++ b/src/ui/activities/setup_activity/callbacks.rs @@ -5,7 +5,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/setup_activity/config.rs b/src/ui/activities/setup_activity/config.rs index 7867c79..fad56d8 100644 --- a/src/ui/activities/setup_activity/config.rs +++ b/src/ui/activities/setup_activity/config.rs @@ -5,7 +5,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/setup_activity/input.rs b/src/ui/activities/setup_activity/input.rs index 38ab98d..cdd7894 100644 --- a/src/ui/activities/setup_activity/input.rs +++ b/src/ui/activities/setup_activity/input.rs @@ -5,7 +5,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/setup_activity/layout.rs b/src/ui/activities/setup_activity/layout.rs index 45ef475..e951f75 100644 --- a/src/ui/activities/setup_activity/layout.rs +++ b/src/ui/activities/setup_activity/layout.rs @@ -5,7 +5,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/setup_activity/misc.rs b/src/ui/activities/setup_activity/misc.rs index 695c015..025cc5c 100644 --- a/src/ui/activities/setup_activity/misc.rs +++ b/src/ui/activities/setup_activity/misc.rs @@ -5,7 +5,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/setup_activity/mod.rs b/src/ui/activities/setup_activity/mod.rs index 724d06c..57ef6ce 100644 --- a/src/ui/activities/setup_activity/mod.rs +++ b/src/ui/activities/setup_activity/mod.rs @@ -5,7 +5,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/context.rs b/src/ui/context.rs index df382f5..1e68941 100644 --- a/src/ui/context.rs +++ b/src/ui/context.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/input.rs b/src/ui/input.rs index bb7931b..87835b6 100644 --- a/src/ui/input.rs +++ b/src/ui/input.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 31da84e..0e8d9c8 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/utils/crypto.rs b/src/utils/crypto.rs index 68faa45..f3dcb08 100644 --- a/src/utils/crypto.rs +++ b/src/utils/crypto.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/utils/fmt.rs b/src/utils/fmt.rs index 939ee02..498f94b 100644 --- a/src/utils/fmt.rs +++ b/src/utils/fmt.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/utils/mod.rs b/src/utils/mod.rs index cb298e1..ea844e7 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/utils/parser.rs b/src/utils/parser.rs index 271f4aa..b2ca6e9 100644 --- a/src/utils/parser.rs +++ b/src/utils/parser.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/utils/random.rs b/src/utils/random.rs index 335f0ae..8622b4c 100644 --- a/src/utils/random.rs +++ b/src/utils/random.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * From eee08bd6230d14c798353a6ee28c568fa80489d6 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Sat, 16 Jan 2021 15:37:19 +0100 Subject: [PATCH 2/9] Key storage (file) --- src/system/keys/filestorage.rs | 160 +++++++++++++++++++++++++++++++++ src/system/keys/mod.rs | 72 +++++++++++++++ src/system/mod.rs | 1 + 3 files changed, 233 insertions(+) create mode 100644 src/system/keys/filestorage.rs create mode 100644 src/system/keys/mod.rs diff --git a/src/system/keys/filestorage.rs b/src/system/keys/filestorage.rs new file mode 100644 index 0000000..da14682 --- /dev/null +++ b/src/system/keys/filestorage.rs @@ -0,0 +1,160 @@ +//! ## FileStorage +//! +//! `filestorage` provides an implementation of the `KeyStorage` trait using a file + +/* +* +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com +* +* This file is part of "TermSCP" +* +* TermSCP 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. +* +* TermSCP 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 TermSCP. If not, see . +* +*/ + +use super::{KeyStorage, KeyStorageError}; + +use std::fs::{OpenOptions, Permissions}; +use std::io::{Read, Write}; +use std::path::{Path, PathBuf}; + +/// ## FileStorage +/// +/// File storage is an implementation o the `KeyStorage` which uses a file to store the key +pub struct FileStorage { + dir_path: PathBuf, +} + +impl FileStorage { + /// ### new + /// + /// Instantiates a new `FileStorage` + pub fn new(dir_path: &Path) -> Self { + FileStorage { + dir_path: PathBuf::from(dir_path), + } + } + + /// ### make_file_path + /// + /// Make file path for key file from `dir_path` and the application id + fn make_file_path(&self, storage_id: &str) -> PathBuf { + let mut p: PathBuf = self.dir_path.clone(); + let file_name = format!(".{}.key", storage_id); + p.push(file_name); + p + } +} + +impl KeyStorage for FileStorage { + /// ### get_key + /// + /// Retrieve key from the key storage. + /// The key might be acccess through an identifier, which identifies + /// the key in the storage + fn get_key(&self, storage_id: &str) -> Result { + let key_file: PathBuf = self.make_file_path(storage_id); + // Check if file exists + if !key_file.exists() { + return Err(KeyStorageError::NoSuchKey); + } + // Read key from file + match OpenOptions::new().read(true).open(key_file.as_path()) { + Ok(mut file) => { + let mut key: String = String::new(); + match file.read_to_string(&mut key) { + Ok(_) => Ok(key), + Err(_) => Err(KeyStorageError::Io), + } + } + Err(_) => Err(KeyStorageError::Io), + } + } + + /// ### set_key + /// + /// Set the key into the key storage + fn set_key(&self, storage_id: &str, key: &str) -> Result<(), KeyStorageError> { + let key_file: PathBuf = self.make_file_path(storage_id); + // Write key + match OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open(key_file.as_path()) + { + Ok(mut file) => { + // Write key to file + if let Err(_) = file.write_all(key.as_bytes()) { + return Err(KeyStorageError::Io); + } + // Set file to readonly + let mut permissions: Permissions = file.metadata().unwrap().permissions(); + permissions.set_readonly(true); + let _ = file.set_permissions(permissions); + Ok(()) + } + Err(_) => Err(KeyStorageError::Io), + } + } + + /// is_supported + /// + /// Returns whether the key storage is supported on the host system + fn is_supported(&self) -> bool { + true + } +} + +#[cfg(test)] +mod tests { + + use super::*; + + #[test] + fn test_system_keys_filestorage_make_dir() { + let storage: FileStorage = FileStorage::new(&Path::new("/tmp/")); + assert_eq!( + storage.make_file_path("bookmarks").as_path(), + Path::new("/tmp/.bookmarks.key") + ); + } + + #[test] + fn test_system_keys_filestorage_ok() { + let key_dir: tempfile::TempDir = + tempfile::TempDir::new().expect("Could not create tempdir"); + let storage: FileStorage = FileStorage::new(key_dir.path()); + let app_name: &str = "termscp"; + let secret: &str = "Th15-15/My-Супер-Секрет"; + // Secret should not exist + assert_eq!( + storage.get_key(app_name).err().unwrap(), + KeyStorageError::NoSuchKey + ); + // Write secret + assert!(storage.set_key(app_name, secret).is_ok()); + // Get secret + assert_eq!(storage.get_key(app_name).ok().unwrap().as_str(), secret); + } + + #[test] + fn test_system_keys_filestorage_err() { + let bad_dir: &Path = Path::new("/piro/poro/pero/"); + let storage: FileStorage = FileStorage::new(bad_dir); + let app_name: &str = "termscp"; + let secret: &str = "Th15-15/My-Супер-Секрет"; + assert!(storage.set_key(app_name, secret).is_err()); + } +} diff --git a/src/system/keys/mod.rs b/src/system/keys/mod.rs new file mode 100644 index 0000000..5ef9802 --- /dev/null +++ b/src/system/keys/mod.rs @@ -0,0 +1,72 @@ +//! ## KeyStorage +//! +//! `keystorage` provides the trait to manipulate to a KeyStorage + +/* +* +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com +* +* This file is part of "TermSCP" +* +* TermSCP 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. +* +* TermSCP 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 TermSCP. If not, see . +* +*/ + +// Storages +pub mod filestorage; + +/// ## KeyStorageError +/// +/// defines the error type for the `KeyStorage` +#[derive(PartialEq, std::fmt::Debug)] +pub enum KeyStorageError { + BadKey, + Io, + NoSuchKey, +} + +impl std::fmt::Display for KeyStorageError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + let err: String = String::from(match &self { + KeyStorageError::BadKey => "Bad key syntax", + KeyStorageError::Io => "Input/Output error", + KeyStorageError::NoSuchKey => "No such key", + }); + write!(f, "{}", err) + } +} + +/// ## KeyStorage +/// +/// this traits provides the methods to communicate and interact with the key storage. +pub trait KeyStorage { + + /// ### get_key + /// + /// Retrieve key from the key storage. + /// The key might be acccess through an identifier, which identifies + /// the key in the storage + fn get_key(&self, storage_id: &str) -> Result; + + /// ### set_key + /// + /// Set the key into the key storage + fn set_key(&self, storage_id: &str, key: &str) -> Result<(), KeyStorageError>; + + /// is_supported + /// + /// Returns whether the key storage is supported on the host system + fn is_supported(&self) -> bool; + +} diff --git a/src/system/mod.rs b/src/system/mod.rs index 2e2e624..371d408 100644 --- a/src/system/mod.rs +++ b/src/system/mod.rs @@ -27,4 +27,5 @@ pub mod bookmarks_client; pub mod config_client; pub mod environment; +pub(crate) mod keys; pub mod sshkey_storage; From 0e4caaecfd3329408228a89eb53646f5aceb2343 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Sat, 16 Jan 2021 16:07:11 +0100 Subject: [PATCH 3/9] Keyring storage --- Cargo.lock | 205 +++++++++++++++++++++++++++++- Cargo.toml | 3 + src/system/keys/filestorage.rs | 11 +- src/system/keys/keyringstorage.rs | 135 ++++++++++++++++++++ src/system/keys/mod.rs | 40 ++++-- 5 files changed, 371 insertions(+), 23 deletions(-) create mode 100644 src/system/keys/keyringstorage.rs diff --git a/Cargo.lock b/Cargo.lock index c1169a0..e3b522f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,16 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "aes" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561" +dependencies = [ + "aes-soft", + "aesni", + "cipher", +] + [[package]] name = "aes-soft" version = "0.6.4" @@ -10,6 +21,16 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "aesni" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" +dependencies = [ + "cipher", + "opaque-debug", +] + [[package]] name = "aho-corasick" version = "0.7.15" @@ -205,16 +226,32 @@ dependencies = [ "memchr", ] +[[package]] +name = "core-foundation" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171" +dependencies = [ + "core-foundation-sys 0.7.0", + "libc", +] + [[package]] name = "core-foundation" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62" dependencies = [ - "core-foundation-sys", + "core-foundation-sys 0.8.2", "libc", ] +[[package]] +name = "core-foundation-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" + [[package]] name = "core-foundation-sys" version = "0.8.2" @@ -272,6 +309,25 @@ dependencies = [ "winapi", ] +[[package]] +name = "crypto-mac" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4857fd85a0c34b3c3297875b747c1e02e06b6a0ea32dd892d8192b9ce0813ea6" +dependencies = [ + "generic-array 0.14.4", + "subtle", +] + +[[package]] +name = "dbus" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4a0c10ea61042b7555729ab0608727bbbb06ce709c11e6047cfa4e10f6d052d" +dependencies = [ + "libc", +] + [[package]] name = "debug-helper" version = "0.3.10" @@ -423,6 +479,26 @@ dependencies = [ "wasi 0.10.0+wasi-snapshot-preview1", ] +[[package]] +name = "hkdf" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51ab2f639c231793c5f6114bdb9bbe50a7dbbfcd7c7c6bd8475dec2d991e964f" +dependencies = [ + "digest 0.9.0", + "hmac", +] + +[[package]] +name = "hmac" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" +dependencies = [ + "crypto-mac", + "digest 0.9.0", +] + [[package]] name = "hostname" version = "0.3.1" @@ -452,6 +528,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "keyring" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bcd64f48199f69993c705fd2f76882e53969db93bc6345021bc8bb6462a9ffa" +dependencies = [ + "byteorder", + "secret-service", + "security-framework 0.4.4", + "winapi", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -594,8 +682,8 @@ dependencies = [ "openssl-probe", "openssl-sys", "schannel", - "security-framework", - "security-framework-sys", + "security-framework 2.0.0", + "security-framework-sys 2.0.0", "tempfile", ] @@ -608,6 +696,40 @@ dependencies = [ "winapi", ] +[[package]] +name = "num" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b7a8e9be5e039e2ff869df49155f1c06bd01ade2117ec783e56ab0932b67a8f" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e9a41747ae4633fce5adffb4d2e81ffc5e89593cb19917f8fb2cc5ff76507bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "747d632c0c558b87dbabbe6a82f3b4ae03720d0646ac5b7b4dae89394be5f2c5" +dependencies = [ + "num-traits", +] + [[package]] name = "num-integer" version = "0.1.44" @@ -618,6 +740,29 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.14" @@ -908,6 +1053,35 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "secret-service" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d752040301c251d653aa740dec847e95767ce312cfc469bee85eb13cbf81d8a" +dependencies = [ + "aes", + "block-modes", + "dbus", + "hkdf", + "lazy_static", + "num", + "rand 0.7.3", + "sha2", +] + +[[package]] +name = "security-framework" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64808902d7d99f78eaddd2b4e2509713babc3dc3c85ad6f4c447680f3c01e535" +dependencies = [ + "bitflags", + "core-foundation 0.7.0", + "core-foundation-sys 0.7.0", + "libc", + "security-framework-sys 0.4.3", +] + [[package]] name = "security-framework" version = "2.0.0" @@ -915,10 +1089,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1759c2e3c8580017a484a7ac56d3abc5a6c1feadf88db2f3633f12ae4268c69" dependencies = [ "bitflags", - "core-foundation", - "core-foundation-sys", + "core-foundation 0.9.1", + "core-foundation-sys 0.8.2", + "libc", + "security-framework-sys 2.0.0", +] + +[[package]] +name = "security-framework-sys" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17bf11d99252f512695eb468de5516e5cf75455521e69dfe343f3b74e4748405" +dependencies = [ + "core-foundation-sys 0.7.0", "libc", - "security-framework-sys", ] [[package]] @@ -927,7 +1111,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f99b9d5e26d2a71633cc4f2ebae7cc9f874044e0c351a27e17892d76dce5678b" dependencies = [ - "core-foundation-sys", + "core-foundation-sys 0.8.2", "libc", ] @@ -1019,6 +1203,12 @@ dependencies = [ "parking_lot 0.10.2", ] +[[package]] +name = "subtle" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" + [[package]] name = "syn" version = "1.0.58" @@ -1058,6 +1248,7 @@ dependencies = [ "ftp4", "getopts", "hostname", + "keyring", "lazy_static", "magic-crypt", "rand 0.8.1", diff --git a/Cargo.toml b/Cargo.toml index 9e1578a..3182414 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,9 @@ whoami = "1.0.1" [target.'cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))'.dependencies] users = "0.11.0" +[target.'cfg(any(target_os = "windows", target_os = "macos"))'.dependencies] +keyring = "0.10.1" + [[bin]] name = "termscp" path = "src/main.rs" diff --git a/src/system/keys/filestorage.rs b/src/system/keys/filestorage.rs index da14682..cce2ff1 100644 --- a/src/system/keys/filestorage.rs +++ b/src/system/keys/filestorage.rs @@ -23,8 +23,9 @@ * */ +// Local use super::{KeyStorage, KeyStorageError}; - +// Ext use std::fs::{OpenOptions, Permissions}; use std::io::{Read, Write}; use std::path::{Path, PathBuf}; @@ -75,10 +76,10 @@ impl KeyStorage for FileStorage { let mut key: String = String::new(); match file.read_to_string(&mut key) { Ok(_) => Ok(key), - Err(_) => Err(KeyStorageError::Io), + Err(_) => Err(KeyStorageError::ProviderError), } } - Err(_) => Err(KeyStorageError::Io), + Err(_) => Err(KeyStorageError::ProviderError), } } @@ -97,7 +98,7 @@ impl KeyStorage for FileStorage { Ok(mut file) => { // Write key to file if let Err(_) = file.write_all(key.as_bytes()) { - return Err(KeyStorageError::Io); + return Err(KeyStorageError::ProviderError); } // Set file to readonly let mut permissions: Permissions = file.metadata().unwrap().permissions(); @@ -105,7 +106,7 @@ impl KeyStorage for FileStorage { let _ = file.set_permissions(permissions); Ok(()) } - Err(_) => Err(KeyStorageError::Io), + Err(_) => Err(KeyStorageError::ProviderError), } } diff --git a/src/system/keys/keyringstorage.rs b/src/system/keys/keyringstorage.rs new file mode 100644 index 0000000..e46bc2e --- /dev/null +++ b/src/system/keys/keyringstorage.rs @@ -0,0 +1,135 @@ +//! ## KeyringStorage +//! +//! `keyringstorage` provides an implementation of the `KeyStorage` trait using the OS keyring + +/* +* +* Copyright (C) 2020-2021 Christian Visintin - christian.visintin1997@gmail.com +* +* This file is part of "TermSCP" +* +* TermSCP 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. +* +* TermSCP 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 TermSCP. If not, see . +* +*/ + +// Deps +extern crate keyring; +// Local +use super::{KeyStorage, KeyStorageError}; +// Ext +use keyring::{Keyring, KeyringError}; + +/// ## KeyringStorage +/// +/// provides a `KeyStorage` implementation using the keyring crate +pub struct KeyringStorage { + username: String, +} + +impl KeyringStorage { + /// ### new + /// + /// Instantiates a new KeyringStorage + pub fn new(username: &str) -> Self { + KeyringStorage { + username: username.to_string(), + } + } +} + +impl KeyStorage for KeyringStorage { + /// ### get_key + /// + /// Retrieve key from the key storage. + /// The key might be acccess through an identifier, which identifies + /// the key in the storage + fn get_key(&self, storage_id: &str) -> Result { + let storage: Keyring = Keyring::new(storage_id, self.username.as_str()); + match storage.get_password() { + Ok(s) => Ok(s), + Err(e) => match e { + KeyringError::NoPasswordFound => Err(KeyStorageError::NoSuchKey), + #[cfg(target_os = "windows")] + KeyringError::WindowsVaultError => Err(KeyStorageError::NoSuchKey), + #[cfg(target_os = "macos")] + KeyringError::MacOsKeychainError(_) => Err(KeyStorageError::NoSuchKey), + _ => panic!("{}", e), + }, + } + } + + /// ### set_key + /// + /// Set the key into the key storage + fn set_key(&self, storage_id: &str, key: &str) -> Result<(), KeyStorageError> { + let storage: Keyring = Keyring::new(storage_id, self.username.as_str()); + match storage.set_password(key) { + Ok(_) => Ok(()), + Err(_) => Err(KeyStorageError::ProviderError), + } + } + + /// is_supported + /// + /// Returns whether the key storage is supported on the host system + fn is_supported(&self) -> bool { + let dummy: String = String::from("dummy-service"); + let storage: Keyring = Keyring::new(dummy.as_str(), self.username.as_str()); + // Check what kind of error is returned + match storage.get_password() { + Ok(_) => true, + Err(err) => match err { + KeyringError::NoBackendFound => false, + //#[cfg(target_os = "macos")] + //KeyringError::MacOsKeychainError(_) => false, + //#[cfg(target_os = "windows")] + //KeyringError::WindowsVaultError => false, + _ => true, + }, + } + } +} + +#[cfg(test)] +mod tests { + + extern crate whoami; + use super::*; + + use whoami::username; + + #[test] + fn test_system_keys_keyringstorage() { + let username: String = username(); + let storage: KeyringStorage = KeyringStorage::new(username.as_str()); + let app_name: &str = "termscp"; + let secret: &str = "Th15-15/My-Супер-Секрет"; + let kring: Keyring = Keyring::new(app_name, username.as_str()); + let _ = kring.delete_password(); + drop(kring); + // Secret should not exist + assert_eq!( + storage.get_key(app_name).err().unwrap(), + KeyStorageError::NoSuchKey + ); + // Write secret + assert!(storage.set_key(app_name, secret).is_ok()); + // Get secret + assert_eq!(storage.get_key(app_name).ok().unwrap().as_str(), secret); + + // Delete the key manually... + let kring: Keyring = Keyring::new(app_name, username.as_str()); + assert!(kring.delete_password().is_ok()); + } +} diff --git a/src/system/keys/mod.rs b/src/system/keys/mod.rs index 5ef9802..02c66b7 100644 --- a/src/system/keys/mod.rs +++ b/src/system/keys/mod.rs @@ -25,22 +25,24 @@ // Storages pub mod filestorage; +#[cfg(any(target_os = "windows", target_os = "macos"))] +pub mod keyringstorage; /// ## KeyStorageError -/// +/// /// defines the error type for the `KeyStorage` #[derive(PartialEq, std::fmt::Debug)] pub enum KeyStorageError { - BadKey, - Io, + //BadKey, + ProviderError, NoSuchKey, } impl std::fmt::Display for KeyStorageError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { let err: String = String::from(match &self { - KeyStorageError::BadKey => "Bad key syntax", - KeyStorageError::Io => "Input/Output error", + //KeyStorageError::BadKey => "Bad key syntax", + KeyStorageError::ProviderError => "Provider service error", KeyStorageError::NoSuchKey => "No such key", }); write!(f, "{}", err) @@ -48,25 +50,41 @@ impl std::fmt::Display for KeyStorageError { } /// ## KeyStorage -/// +/// /// this traits provides the methods to communicate and interact with the key storage. pub trait KeyStorage { - /// ### get_key - /// + /// /// Retrieve key from the key storage. /// The key might be acccess through an identifier, which identifies /// the key in the storage fn get_key(&self, storage_id: &str) -> Result; /// ### set_key - /// + /// /// Set the key into the key storage fn set_key(&self, storage_id: &str, key: &str) -> Result<(), KeyStorageError>; /// is_supported - /// + /// /// Returns whether the key storage is supported on the host system fn is_supported(&self) -> bool; - +} + +#[cfg(test)] +mod tests { + + use super::*; + + #[test] + fn test_system_keys_mod_errors() { + assert_eq!( + format!("{}", KeyStorageError::ProviderError), + String::from("Provider service error") + ); + assert_eq!( + format!("{}", KeyStorageError::NoSuchKey), + String::from("No such key") + ); + } } From 0192b86422d3f391975a62fb1b5a4e474569d7a3 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Sat, 16 Jan 2021 16:07:53 +0100 Subject: [PATCH 4/9] Check if supported (test) --- src/system/keys/filestorage.rs | 2 ++ src/system/keys/keyringstorage.rs | 1 + 2 files changed, 3 insertions(+) diff --git a/src/system/keys/filestorage.rs b/src/system/keys/filestorage.rs index cce2ff1..189fc73 100644 --- a/src/system/keys/filestorage.rs +++ b/src/system/keys/filestorage.rs @@ -137,6 +137,8 @@ mod tests { let key_dir: tempfile::TempDir = tempfile::TempDir::new().expect("Could not create tempdir"); let storage: FileStorage = FileStorage::new(key_dir.path()); + // Supported + assert!(storage.is_supported()); let app_name: &str = "termscp"; let secret: &str = "Th15-15/My-Супер-Секрет"; // Secret should not exist diff --git a/src/system/keys/keyringstorage.rs b/src/system/keys/keyringstorage.rs index e46bc2e..9eb29ab 100644 --- a/src/system/keys/keyringstorage.rs +++ b/src/system/keys/keyringstorage.rs @@ -113,6 +113,7 @@ mod tests { fn test_system_keys_keyringstorage() { let username: String = username(); let storage: KeyringStorage = KeyringStorage::new(username.as_str()); + assert!(storage.is_supported()); let app_name: &str = "termscp"; let secret: &str = "Th15-15/My-Супер-Секрет"; let kring: Keyring = Keyring::new(app_name, username.as_str()); From 08d8a3621c36bf305ad5eeee0a0d3b4a725156f8 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Sat, 16 Jan 2021 16:57:00 +0100 Subject: [PATCH 5/9] Keyring storage in bookmarks client (if possible) --- src/system/bookmarks_client.rs | 126 +++++++++---------- src/system/environment.rs | 13 +- src/system/keys/keyringstorage.rs | 2 +- src/ui/activities/auth_activity/bookmarks.rs | 14 ++- 4 files changed, 74 insertions(+), 81 deletions(-) diff --git a/src/system/bookmarks_client.rs b/src/system/bookmarks_client.rs index 3c9510f..cec7d77 100644 --- a/src/system/bookmarks_client.rs +++ b/src/system/bookmarks_client.rs @@ -23,6 +23,12 @@ * */ +// Deps +extern crate whoami; +// Crate +#[cfg(any(target_os = "windows", target_os = "macos"))] +use super::keys::keyringstorage::KeyringStorage; +use super::keys::{filestorage::FileStorage, KeyStorage, KeyStorageError}; // Local use crate::bookmarks::serializer::BookmarkSerializer; use crate::bookmarks::{Bookmark, SerializerError, SerializerErrorKind, UserHosts}; @@ -31,8 +37,7 @@ use crate::utils::crypto; use crate::utils::fmt::fmt_time; use crate::utils::random::random_alphanumeric_with_len; // Ext -use std::fs::{OpenOptions, Permissions}; -use std::io::{Read, Write}; +use std::fs::OpenOptions; use std::path::{Path, PathBuf}; use std::str::FromStr; use std::string::ToString; @@ -53,23 +58,60 @@ impl BookmarksClient { /// /// Instantiates a new BookmarksClient /// Bookmarks file path must be provided - /// Key file must be provided + /// Storage path for file provider must be provided pub fn new( bookmarks_file: &Path, - key_file: &Path, + storage_path: &Path, recents_size: usize, ) -> Result { // Create default hosts let default_hosts: UserHosts = Default::default(); - // If key file doesn't exist, create key, otherwise read it - let key: String = match key_file.exists() { - true => match BookmarksClient::load_key(key_file) { - Ok(key) => key, - Err(err) => return Err(err), - }, - false => match BookmarksClient::generate_key(key_file) { - Ok(key) => key, - Err(err) => return Err(err), + // Make a key storage (windows / macos) + #[cfg(any(target_os = "windows", target_os = "macos"))] + let (key_storage, service_id): (Box, &str) = { + let username: String = whoami::username(); + let storage: KeyringStorage = KeyringStorage::new(username.as_str()); + // Check if keyring storage is supported + #[cfg(not(test))] + let app_name: &str = "termscp"; + #[cfg(test)] // NOTE: when running test, add -test + let app_name: &str = "termscp-test"; + match storage.is_supported() { + true => (Box::new(storage), app_name), + false => (Box::new(FileStorage::new(storage_path)), "bookmarks"), + } + }; + // Make a key storage (linux / unix) + #[cfg(any(target_os = "linux", target_os = "unix"))] + let (key_storage, service_id): (Box, &str) = { + #[cfg(not(test))] + let app_name: &str = "bookmarks"; + #[cfg(test)] // NOTE: when running test, add -test + let app_name: &str = "bookmarks-test"; + (Box::new(FileStorage::new(storage_path)), app_name) + }; + // Load key + let key: String = match key_storage.get_key(service_id) { + Ok(k) => k, + Err(e) => match e { + KeyStorageError::NoSuchKey => { + // If no such key, generate key and set it into the storage + let key: String = Self::generate_key(); + if let Err(e) = key_storage.set_key(service_id, key.as_str()) { + return Err(SerializerError::new_ex( + SerializerErrorKind::IoError, + format!("Could not write key to storage: {}", e), + )); + } + // Return key + key + } + _ => { + return Err(SerializerError::new_ex( + SerializerErrorKind::IoError, + format!("Could not get key from storage: {}", e), + )) + } }, }; let mut client: BookmarksClient = BookmarksClient { @@ -276,36 +318,10 @@ impl BookmarksClient { /// ### generate_key /// - /// Generate a new AES key and write it to key file - fn generate_key(key_file: &Path) -> Result { + /// Generate a new AES key + fn generate_key() -> String { // Generate 256 bytes (2048 bits) key - let key: String = random_alphanumeric_with_len(256); - // Write file - match OpenOptions::new() - .create(true) - .write(true) - .truncate(true) - .open(key_file) - { - Ok(mut file) => { - // Write key to file - if let Err(err) = file.write_all(key.as_bytes()) { - return Err(SerializerError::new_ex( - SerializerErrorKind::IoError, - err.to_string(), - )); - } - // Set file to readonly - let mut permissions: Permissions = file.metadata().unwrap().permissions(); - permissions.set_readonly(true); - let _ = file.set_permissions(permissions); - Ok(key) - } - Err(err) => Err(SerializerError::new_ex( - SerializerErrorKind::IoError, - err.to_string(), - )), - } + random_alphanumeric_with_len(256) } /// ### make_bookmark @@ -331,28 +347,6 @@ impl BookmarksClient { } } - /// ### load_key - /// - /// Load key from key_file - fn load_key(key_file: &Path) -> Result { - match OpenOptions::new().read(true).open(key_file) { - Ok(mut file) => { - let mut key: String = String::with_capacity(256); - match file.read_to_string(&mut key) { - Ok(_) => Ok(key), - Err(err) => Err(SerializerError::new_ex( - SerializerErrorKind::IoError, - err.to_string(), - )), - } - } - Err(err) => Err(SerializerError::new_ex( - SerializerErrorKind::IoError, - err.to_string(), - )), - } - } - /// ### encrypt_str /// /// Encrypt provided string using AES-128. Encrypted buffer is then converted to BASE64 @@ -397,6 +391,7 @@ mod tests { } #[test] + #[cfg(any(target_os = "unix", target_os = "linux"))] fn test_system_bookmarks_new_err() { assert!(BookmarksClient::new( Path::new("/tmp/oifoif/omar"), @@ -647,9 +642,8 @@ mod tests { /// /// Get paths for configuration and key for bookmarks fn get_paths(dir: &Path) -> (PathBuf, PathBuf) { - let mut k: PathBuf = PathBuf::from(dir); + let k: PathBuf = PathBuf::from(dir); let mut c: PathBuf = k.clone(); - k.push("bookmarks.key"); c.push("bookmarks.toml"); (c, k) } diff --git a/src/system/environment.rs b/src/system/environment.rs index 0b994ae..b9c7973 100644 --- a/src/system/environment.rs +++ b/src/system/environment.rs @@ -59,14 +59,12 @@ pub fn init_config_dir() -> Result, String> { /// ### get_bookmarks_paths /// /// Get paths for bookmarks client -/// Returns: path of bookmarks.toml and path of key -pub fn get_bookmarks_paths(config_dir: &Path) -> (PathBuf, PathBuf) { +/// Returns: path of bookmarks.toml +pub fn get_bookmarks_paths(config_dir: &Path) -> PathBuf { // Prepare paths let mut bookmarks_file: PathBuf = PathBuf::from(config_dir); bookmarks_file.push("bookmarks.toml"); - let mut key_file: PathBuf = PathBuf::from(config_dir); - key_file.push(".bookmarks.key"); // key file is hidden - (bookmarks_file, key_file) + bookmarks_file } /// ### get_config_paths @@ -123,10 +121,7 @@ mod tests { fn test_system_environment_get_bookmarks_paths() { assert_eq!( get_bookmarks_paths(&Path::new("/home/omar/.config/termscp/")), - ( - PathBuf::from("/home/omar/.config/termscp/bookmarks.toml"), - PathBuf::from("/home/omar/.config/termscp/.bookmarks.key") - ) + PathBuf::from("/home/omar/.config/termscp/bookmarks.toml"), ); } diff --git a/src/system/keys/keyringstorage.rs b/src/system/keys/keyringstorage.rs index 9eb29ab..93f85c0 100644 --- a/src/system/keys/keyringstorage.rs +++ b/src/system/keys/keyringstorage.rs @@ -114,7 +114,7 @@ mod tests { let username: String = username(); let storage: KeyringStorage = KeyringStorage::new(username.as_str()); assert!(storage.is_supported()); - let app_name: &str = "termscp"; + let app_name: &str = "termscp-test2"; let secret: &str = "Th15-15/My-Супер-Секрет"; let kring: Keyring = Keyring::new(app_name, username.as_str()); let _ = kring.delete_password(); diff --git a/src/ui/activities/auth_activity/bookmarks.rs b/src/ui/activities/auth_activity/bookmarks.rs index f9f553d..0e2f99c 100644 --- a/src/ui/activities/auth_activity/bookmarks.rs +++ b/src/ui/activities/auth_activity/bookmarks.rs @@ -224,11 +224,15 @@ impl AuthActivity { match environment::init_config_dir() { Ok(path) => { // If some configure client, otherwise do nothing; don't bother users telling them that bookmarks are not supported on their system. - if let Some(path) = path { - let (bookmarks_file, key_file): (PathBuf, PathBuf) = - environment::get_bookmarks_paths(path.as_path()); + if let Some(config_dir_path) = path { + let bookmarks_file: PathBuf = + environment::get_bookmarks_paths(config_dir_path.as_path()); // Initialize client - match BookmarksClient::new(bookmarks_file.as_path(), key_file.as_path(), 16) { + match BookmarksClient::new( + bookmarks_file.as_path(), + config_dir_path.as_path(), + 16, + ) { Ok(cli) => self.bookmarks_client = Some(cli), Err(err) => { self.popup = Some(Popup::Alert( @@ -236,7 +240,7 @@ impl AuthActivity { format!( "Could not initialize bookmarks (at \"{}\", \"{}\"): {}", bookmarks_file.display(), - key_file.display(), + config_dir_path.display(), err ), )) From 1acbf897178b520129ee75c7ff99d7c79fbc3b74 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Sat, 16 Jan 2021 17:13:41 +0100 Subject: [PATCH 6/9] keyring ok --- CHANGELOG.md | 3 +++ README.md | 8 +++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index db09900..612117d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,11 +15,14 @@ FIXME: Released on ??? +- **Keyring to store secrets** + - On both MacOS and Windows, the secret used to encrypt passwords in bookmarks it is now store in the OS secret vault. This provides much more security to store the password - Enhancements: - Added connection timeout to 30 seconds to SFTP/SCP clients and improved name lookup system. - Bugfix: - Solved index in explorer files list which was no more kept after 0.3.0 - SCP file transfer: fixed possible wrong file size when sending file, due to a possible incoherent size between the file explorer and the actual file size. +- Breaking changes: on **MacOS / Windows systems only**, the password you saved for bookmarks won't be working anymore if you have support for the keyring crate. Because of the migration to keyring, the previously used secret hasn't been migrated to the storage, instead a new secret will be used. To solve this, just save the bookmark again with the password. ## 0.3.0 diff --git a/README.md b/README.md index ab59bcc..1bf9150 100644 --- a/README.md +++ b/README.md @@ -233,7 +233,12 @@ If you go to [gallery](#gallery-), there is a GIF showing how bookmarks work ### Are my passwords Safe 😈 Well, kinda. -As said before, bookmarks are saved in your configuration directory along with passwords. Passwords are obviously not plain text, they are encrypted with **AES-128**. Does this make them safe? Well, no, the key used to encrypt your passwords is generated at the first launch of termscp and stored on your drive. So it's still possible to retrieve the key to decrypt passwords. Luckily, the location of the key guarantees your key can't be read by users different from yours, but yeah, I still wouldn't save the password for a server exposed on the internet 😉. +As said before, bookmarks are saved in your configuration directory along with passwords. Passwords are obviously not plain text, they are encrypted with **AES-128**. Does this make them safe? Well, depends on your operating system: + +On Windows and MacOS the passwords are (if possible, but should be) in respectively the Windows Vault and the Keychain. This is actually super-safe and is directly managed by your operating system. + +On Linux and BSD, on the other hand the key used to encrypt your passwords is stored on your drive. So it's still possible to retrieve the key to decrypt passwords. Luckily, the location of the key guarantees your key can't be read by users different from yours, but yeah, I still wouldn't save the password for a server exposed on the internet 😉. +Actually [keyring-rs](https://github.com/hwchen/keyring-rs), supports Linux, but for different reasons I preferred not to make it available for this configuration. If you want to read more about my decision read [this issue](https://github.com/veeso/termscp/issues/2), while if you think this might have been implemented differently feel free to open an issue with your proposal. --- @@ -357,6 +362,7 @@ TermSCP is powered by these aweseome projects: - [bytesize](https://github.com/hyunsik/bytesize) - [crossterm](https://github.com/crossterm-rs/crossterm) - [edit](https://github.com/milkey-mouse/edit) +- [keyring-rs](https://github.com/hwchen/keyring-rs) - [rpassword](https://github.com/conradkleinespel/rpassword) - [rust-ftp](https://github.com/mattnenterprise/rust-ftp) - [ssh2-rs](https://github.com/alexcrichton/ssh2-rs) From cb20589b019315231dd8d5e54307910620d7b171 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Sat, 16 Jan 2021 17:27:07 +0100 Subject: [PATCH 7/9] Macos test thread (?) --- .github/workflows/macos.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 54f707e..4fbcbd2 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -14,6 +14,6 @@ jobs: - name: Build run: cargo build --verbose - name: Run tests - run: cargo test --verbose + run: cargo test --verbose -- --test-threads=1 - name: Clippy run: cargo clippy From ac02928e69d136e567a84f36a5af6588ceb4bec9 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Sat, 16 Jan 2021 17:37:03 +0100 Subject: [PATCH 8/9] Don't run bookmarks tests on macos --- .github/workflows/macos.yml | 2 +- src/system/bookmarks_client.rs | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 4fbcbd2..54f707e 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -14,6 +14,6 @@ jobs: - name: Build run: cargo build --verbose - name: Run tests - run: cargo test --verbose -- --test-threads=1 + run: cargo test --verbose - name: Clippy run: cargo clippy diff --git a/src/system/bookmarks_client.rs b/src/system/bookmarks_client.rs index cec7d77..825e4eb 100644 --- a/src/system/bookmarks_client.rs +++ b/src/system/bookmarks_client.rs @@ -376,6 +376,7 @@ mod tests { use std::time::Duration; #[test] + #[cfg(not(target_os = "macos"))] // CI/CD blocks fn test_system_bookmarks_new() { let tmp_dir: tempfile::TempDir = create_tmp_dir(); let (cfg_path, key_path): (PathBuf, PathBuf) = get_paths(tmp_dir.path()); @@ -408,6 +409,7 @@ mod tests { } #[test] + #[cfg(not(target_os = "macos"))] // CI/CD blocks fn test_system_bookmarks_new_from_existing() { let tmp_dir: tempfile::TempDir = create_tmp_dir(); let (cfg_path, key_path): (PathBuf, PathBuf) = get_paths(tmp_dir.path()); @@ -453,6 +455,7 @@ mod tests { } #[test] + #[cfg(not(target_os = "macos"))] // CI/CD blocks fn test_system_bookmarks_manipulate_bookmarks() { let tmp_dir: tempfile::TempDir = create_tmp_dir(); let (cfg_path, key_path): (PathBuf, PathBuf) = get_paths(tmp_dir.path()); @@ -498,6 +501,7 @@ mod tests { #[test] #[should_panic] + #[cfg(not(target_os = "macos"))] // CI/CD blocks fn test_system_bookmarks_bad_bookmark_name() { let tmp_dir: tempfile::TempDir = create_tmp_dir(); let (cfg_path, key_path): (PathBuf, PathBuf) = get_paths(tmp_dir.path()); @@ -516,6 +520,7 @@ mod tests { } #[test] + #[cfg(not(target_os = "macos"))] // CI/CD blocks fn test_system_bookmarks_manipulate_recents() { let tmp_dir: tempfile::TempDir = create_tmp_dir(); let (cfg_path, key_path): (PathBuf, PathBuf) = get_paths(tmp_dir.path()); @@ -550,6 +555,7 @@ mod tests { } #[test] + #[cfg(not(target_os = "macos"))] // CI/CD blocks fn test_system_bookmarks_dup_recent() { let tmp_dir: tempfile::TempDir = create_tmp_dir(); let (cfg_path, key_path): (PathBuf, PathBuf) = get_paths(tmp_dir.path()); @@ -574,6 +580,7 @@ mod tests { } #[test] + #[cfg(not(target_os = "macos"))] // CI/CD blocks fn test_system_bookmarks_recents_more_than_limit() { let tmp_dir: tempfile::TempDir = create_tmp_dir(); let (cfg_path, key_path): (PathBuf, PathBuf) = get_paths(tmp_dir.path()); @@ -621,6 +628,7 @@ mod tests { #[test] #[should_panic] + #[cfg(not(target_os = "macos"))] // CI/CD blocks fn test_system_bookmarks_add_bookmark_empty() { let tmp_dir: tempfile::TempDir = create_tmp_dir(); let (cfg_path, key_path): (PathBuf, PathBuf) = get_paths(tmp_dir.path()); From 23ca2baa8ce9df0d3cc75ab206129142f88c89ae Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Sat, 16 Jan 2021 18:02:12 +0100 Subject: [PATCH 9/9] Cargo clippy --- src/activity_manager.rs | 6 +++--- src/filetransfer/ftp_transfer.rs | 15 +++++++-------- src/filetransfer/scp_transfer.rs | 5 +---- src/fs/explorer/mod.rs | 7 +++---- src/main.rs | 4 ++-- src/system/bookmarks_client.rs | 19 +++++++++++-------- src/system/keys/filestorage.rs | 2 +- src/system/keys/keyringstorage.rs | 9 +-------- 8 files changed, 29 insertions(+), 38 deletions(-) diff --git a/src/activity_manager.rs b/src/activity_manager.rs index b8964a0..130381e 100644 --- a/src/activity_manager.rs +++ b/src/activity_manager.rs @@ -27,7 +27,7 @@ use std::path::PathBuf; // Deps use crate::filetransfer::FileTransferProtocol; -use crate::host::Localhost; +use crate::host::{HostError, Localhost}; use crate::ui::activities::{ auth_activity::AuthActivity, filetransfer_activity::FileTransferActivity, filetransfer_activity::FileTransferParams, setup_activity::SetupActivity, Activity, @@ -60,11 +60,11 @@ impl ActivityManager { /// ### new /// /// Initializes a new Activity Manager - pub fn new(local_dir: &PathBuf, interval: Duration) -> Result { + pub fn new(local_dir: &PathBuf, interval: Duration) -> Result { // Prepare Context let host: Localhost = match Localhost::new(local_dir.clone()) { Ok(h) => h, - Err(_) => return Err(()), + Err(e) => return Err(e), }; let ctx: Context = Context::new(host); Ok(ActivityManager { diff --git a/src/filetransfer/ftp_transfer.rs b/src/filetransfer/ftp_transfer.rs index bee6440..8c1d065 100644 --- a/src/filetransfer/ftp_transfer.rs +++ b/src/filetransfer/ftp_transfer.rs @@ -180,10 +180,12 @@ impl FtpFileTransfer { Err(_) => None, }; // Get filesize - let filesize: usize = match metadata.get(6).unwrap().as_str().parse::() { - Ok(sz) => sz, - Err(_) => 0, - }; + let filesize: usize = metadata + .get(6) + .unwrap() + .as_str() + .parse::() + .unwrap_or(0); let file_name: String = String::from(metadata.get(8).unwrap().as_str()); // Check if file_name is '.' or '..' if file_name.as_str() == "." || file_name.as_str() == ".." { @@ -270,10 +272,7 @@ impl FtpFileTransfer { true => 0, // If is directory, filesize is 0 false => match metadata.get(3) { // If is file, parse arg 3 - Some(val) => match val.as_str().parse::() { - Ok(sz) => sz, - Err(_) => 0, - }, + Some(val) => val.as_str().parse::().unwrap_or(0), None => 0, // Should not happen }, }; diff --git a/src/filetransfer/scp_transfer.rs b/src/filetransfer/scp_transfer.rs index 0b8cafa..db2d2c2 100644 --- a/src/filetransfer/scp_transfer.rs +++ b/src/filetransfer/scp_transfer.rs @@ -167,10 +167,7 @@ impl ScpFileTransfer { Err(_) => None, }; // Get filesize - let filesize: usize = match metadata.get(6).unwrap().as_str().parse::() { - Ok(sz) => sz, - Err(_) => 0, - }; + let filesize: usize = metadata.get(6).unwrap().as_str().parse::().unwrap_or(0); // Get link and name let (file_name, symlink_path): (String, Option) = match is_symlink { true => self.get_name_and_link(metadata.get(8).unwrap().as_str()), diff --git a/src/fs/explorer/mod.rs b/src/fs/explorer/mod.rs index 6cc41cf..ffc8ea3 100644 --- a/src/fs/explorer/mod.rs +++ b/src/fs/explorer/mod.rs @@ -30,6 +30,7 @@ extern crate bitflags; // Locals use super::FsEntry; // Ext +use std::cmp::Reverse; use std::collections::VecDeque; use std::path::{Path, PathBuf}; use std::str::FromStr; @@ -238,16 +239,14 @@ impl FileExplorer { /// /// Sort files by creation time; the newest comes first fn sort_files_by_creation_time(&mut self) { - self.files - .sort_by(|a: &FsEntry, b: &FsEntry| b.get_creation_time().cmp(&a.get_creation_time())); + self.files.sort_by_key(|b: &FsEntry| Reverse(b.get_creation_time())); } /// ### sort_files_by_size /// /// Sort files by size fn sort_files_by_size(&mut self) { - self.files - .sort_by(|a: &FsEntry, b: &FsEntry| b.get_size().cmp(&a.get_size())); + self.files.sort_by_key(|b: &FsEntry| Reverse(b.get_size())); } /// ### sort_files_directories_first diff --git a/src/main.rs b/src/main.rs index 52de229..76d4580 100644 --- a/src/main.rs +++ b/src/main.rs @@ -167,8 +167,8 @@ fn main() { // Create activity manager (and context too) let mut manager: ActivityManager = match ActivityManager::new(&wrkdir, ticks) { Ok(m) => m, - Err(_) => { - eprintln!("Invalid directory '{}'", wrkdir.display()); + Err(err) => { + eprintln!("Could not start activity manager: {}", err); std::process::exit(255); } }; diff --git a/src/system/bookmarks_client.rs b/src/system/bookmarks_client.rs index 825e4eb..3b7aac9 100644 --- a/src/system/bookmarks_client.rs +++ b/src/system/bookmarks_client.rs @@ -369,6 +369,7 @@ impl BookmarksClient { } #[cfg(test)] +#[cfg(not(target_os = "macos"))] // CI/CD blocks mod tests { use super::*; @@ -376,7 +377,7 @@ mod tests { use std::time::Duration; #[test] - #[cfg(not(target_os = "macos"))] // CI/CD blocks + fn test_system_bookmarks_new() { let tmp_dir: tempfile::TempDir = create_tmp_dir(); let (cfg_path, key_path): (PathBuf, PathBuf) = get_paths(tmp_dir.path()); @@ -409,7 +410,7 @@ mod tests { } #[test] - #[cfg(not(target_os = "macos"))] // CI/CD blocks + fn test_system_bookmarks_new_from_existing() { let tmp_dir: tempfile::TempDir = create_tmp_dir(); let (cfg_path, key_path): (PathBuf, PathBuf) = get_paths(tmp_dir.path()); @@ -455,7 +456,7 @@ mod tests { } #[test] - #[cfg(not(target_os = "macos"))] // CI/CD blocks + fn test_system_bookmarks_manipulate_bookmarks() { let tmp_dir: tempfile::TempDir = create_tmp_dir(); let (cfg_path, key_path): (PathBuf, PathBuf) = get_paths(tmp_dir.path()); @@ -501,7 +502,7 @@ mod tests { #[test] #[should_panic] - #[cfg(not(target_os = "macos"))] // CI/CD blocks + fn test_system_bookmarks_bad_bookmark_name() { let tmp_dir: tempfile::TempDir = create_tmp_dir(); let (cfg_path, key_path): (PathBuf, PathBuf) = get_paths(tmp_dir.path()); @@ -520,7 +521,7 @@ mod tests { } #[test] - #[cfg(not(target_os = "macos"))] // CI/CD blocks + fn test_system_bookmarks_manipulate_recents() { let tmp_dir: tempfile::TempDir = create_tmp_dir(); let (cfg_path, key_path): (PathBuf, PathBuf) = get_paths(tmp_dir.path()); @@ -555,7 +556,7 @@ mod tests { } #[test] - #[cfg(not(target_os = "macos"))] // CI/CD blocks + fn test_system_bookmarks_dup_recent() { let tmp_dir: tempfile::TempDir = create_tmp_dir(); let (cfg_path, key_path): (PathBuf, PathBuf) = get_paths(tmp_dir.path()); @@ -580,7 +581,7 @@ mod tests { } #[test] - #[cfg(not(target_os = "macos"))] // CI/CD blocks + fn test_system_bookmarks_recents_more_than_limit() { let tmp_dir: tempfile::TempDir = create_tmp_dir(); let (cfg_path, key_path): (PathBuf, PathBuf) = get_paths(tmp_dir.path()); @@ -628,7 +629,7 @@ mod tests { #[test] #[should_panic] - #[cfg(not(target_os = "macos"))] // CI/CD blocks + fn test_system_bookmarks_add_bookmark_empty() { let tmp_dir: tempfile::TempDir = create_tmp_dir(); let (cfg_path, key_path): (PathBuf, PathBuf) = get_paths(tmp_dir.path()); @@ -649,6 +650,7 @@ mod tests { /// ### get_paths /// /// Get paths for configuration and key for bookmarks + fn get_paths(dir: &Path) -> (PathBuf, PathBuf) { let k: PathBuf = PathBuf::from(dir); let mut c: PathBuf = k.clone(); @@ -659,6 +661,7 @@ mod tests { /// ### create_tmp_dir /// /// Create temporary directory + fn create_tmp_dir() -> tempfile::TempDir { tempfile::TempDir::new().ok().unwrap() } diff --git a/src/system/keys/filestorage.rs b/src/system/keys/filestorage.rs index 189fc73..fe9e921 100644 --- a/src/system/keys/filestorage.rs +++ b/src/system/keys/filestorage.rs @@ -97,7 +97,7 @@ impl KeyStorage for FileStorage { { Ok(mut file) => { // Write key to file - if let Err(_) = file.write_all(key.as_bytes()) { + if file.write_all(key.as_bytes()).is_err() { return Err(KeyStorageError::ProviderError); } // Set file to readonly diff --git a/src/system/keys/keyringstorage.rs b/src/system/keys/keyringstorage.rs index 93f85c0..0e3662d 100644 --- a/src/system/keys/keyringstorage.rs +++ b/src/system/keys/keyringstorage.rs @@ -89,14 +89,7 @@ impl KeyStorage for KeyringStorage { // Check what kind of error is returned match storage.get_password() { Ok(_) => true, - Err(err) => match err { - KeyringError::NoBackendFound => false, - //#[cfg(target_os = "macos")] - //KeyringError::MacOsKeychainError(_) => false, - //#[cfg(target_os = "windows")] - //KeyringError::WindowsVaultError => false, - _ => true, - }, + Err(err) => !matches!(err, KeyringError::NoBackendFound), } } }