-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
54 changed files
with
2,015 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
using System; | ||
using System.ComponentModel; | ||
using System.Runtime.InteropServices; | ||
using System.Threading; | ||
|
||
namespace PassManager.Console.Clipboard | ||
{ | ||
public static class WindowsClipboard | ||
{ | ||
private const uint UNICODE = 13; | ||
|
||
public static void SetText(string text) | ||
{ | ||
OpenClipboard(); | ||
SetClipboardText(text); | ||
} | ||
|
||
private static void OpenClipboard() | ||
{ | ||
var retryCount = 5; | ||
while (true) | ||
{ | ||
if (OpenClipboard(default)) | ||
{ | ||
break; | ||
} | ||
|
||
if (--retryCount == 0) | ||
{ | ||
ThrowWin32Exception(); | ||
} | ||
|
||
Thread.Sleep(50); | ||
} | ||
} | ||
|
||
private static void SetClipboardText(string text) | ||
{ | ||
IntPtr hGlobal = default; | ||
try | ||
{ | ||
EmptyClipboard(); | ||
|
||
var allocSize = (text.Length + 1) * 2; | ||
hGlobal = Marshal.AllocHGlobal(allocSize); | ||
if (hGlobal == default) | ||
{ | ||
ThrowWin32Exception(); | ||
} | ||
|
||
var target = GlobalLock(hGlobal); | ||
if (target == default) | ||
{ | ||
ThrowWin32Exception(); | ||
} | ||
|
||
try | ||
{ | ||
Marshal.Copy(text.ToCharArray(), 0, target, text.Length); | ||
} | ||
finally | ||
{ | ||
GlobalUnlock(target); | ||
} | ||
|
||
if (SetClipboardData(UNICODE, hGlobal) == default) | ||
{ | ||
ThrowWin32Exception(); | ||
} | ||
|
||
hGlobal = default; | ||
} | ||
finally | ||
{ | ||
if (hGlobal != default) | ||
{ | ||
Marshal.FreeHGlobal(hGlobal); | ||
} | ||
|
||
CloseClipboard(); | ||
} | ||
} | ||
|
||
private static void ThrowWin32Exception() | ||
{ | ||
throw new Win32Exception(Marshal.GetLastWin32Error()); | ||
} | ||
|
||
[DllImport("kernel32.dll", SetLastError = true)] | ||
static extern IntPtr GlobalLock(IntPtr hMem); | ||
|
||
[DllImport("kernel32.dll", SetLastError = true)] | ||
[return: MarshalAs(UnmanagedType.Bool)] | ||
static extern bool GlobalUnlock(IntPtr hMem); | ||
|
||
[DllImport("user32.dll", SetLastError = true)] | ||
[return: MarshalAs(UnmanagedType.Bool)] | ||
static extern bool OpenClipboard(IntPtr hWndNewOwner); | ||
|
||
[DllImport("user32.dll", SetLastError = true)] | ||
[return: MarshalAs(UnmanagedType.Bool)] | ||
static extern bool CloseClipboard(); | ||
|
||
[DllImport("user32.dll", SetLastError = true)] | ||
static extern IntPtr SetClipboardData(uint uFormat, IntPtr data); | ||
|
||
[DllImport("user32.dll")] | ||
static extern bool EmptyClipboard(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
using PassManager.Console.Commands.Settings; | ||
using PassManager.Console.Extensions; | ||
using PassManager.Core.Repository; | ||
using Spectre.Console; | ||
using Spectre.Console.Cli; | ||
using System.Collections.Generic; | ||
using System.Threading.Tasks; | ||
|
||
namespace PassManager.Console.Commands | ||
{ | ||
public sealed class AddPasswordCommand : BasePasswordAsyncCommand<AddPasswordSettings> | ||
{ | ||
public AddPasswordCommand(IPasswordManager passwordManager) : base(passwordManager) | ||
{ | ||
} | ||
|
||
public override async Task<int> ExecuteAsync(CommandContext context, AddPasswordSettings settings) | ||
{ | ||
var password = this.AskPassword(); | ||
var customSecret = this.AskCustomSecret(settings); | ||
var tags = this.AskTags(settings); | ||
|
||
var result = await this.passwordManager.CreatePasswordAsync(settings.Name, password, customSecret, tags); | ||
result.PrintConsoleErrorOrMessage($"[green]Password for {settings.Name} saved[/]"); | ||
|
||
return 0; | ||
} | ||
|
||
private string AskPassword() | ||
{ | ||
var passwordPrompt = new TextPrompt<string>("Enter [darkolivegreen2]password[/]:") | ||
.Secret() | ||
.Validate(v => !string.IsNullOrEmpty(v), "Password must be provided"); | ||
|
||
return AnsiConsole.Prompt(passwordPrompt); | ||
} | ||
|
||
private string AskCustomSecret(AddPasswordSettings settings) | ||
{ | ||
string customSecret = null; | ||
if (settings.ApplyCustomSecret) | ||
{ | ||
var customSecretPrompt = new TextPrompt<string>("Enter [darkolivegreen2]custom secret[/]:") | ||
.Secret() | ||
.Validate(v => !string.IsNullOrEmpty(v), "Secret value cannot be empty"); | ||
|
||
customSecret = AnsiConsole.Prompt(customSecretPrompt); | ||
} | ||
return customSecret; | ||
} | ||
|
||
private List<string> AskTags(AddPasswordSettings settings) | ||
{ | ||
var tags = new List<string>(); | ||
if (settings.AddTags) | ||
{ | ||
AnsiConsole.MarkupLine("Enter tags one by one or leave value as empty and press enter to continue."); | ||
var tagValuePrompt = new TextPrompt<string>( | ||
"Enter [darkolivegreen2]tag value[/]:") | ||
.AllowEmpty() | ||
.PromptStyle("red"); | ||
|
||
while (true) | ||
{ | ||
var tagValue = AnsiConsole.Prompt(tagValuePrompt); | ||
if (string.IsNullOrEmpty(tagValue)) | ||
{ | ||
break; | ||
} | ||
|
||
tags.Add(tagValue); | ||
} | ||
} | ||
|
||
return tags; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
using PassManager.Core.Repository; | ||
using PassManager.Core.VirtualDirectory; | ||
using Spectre.Console; | ||
using Spectre.Console.Cli; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
|
||
namespace PassManager.Console.Commands | ||
{ | ||
public abstract class BasePasswordAsyncCommand<T> : AsyncCommand<T> where T : CommandSettings | ||
{ | ||
protected readonly IPasswordManager passwordManager; | ||
|
||
protected BasePasswordAsyncCommand(IPasswordManager passwordManager) | ||
{ | ||
this.passwordManager = passwordManager; | ||
} | ||
|
||
protected async Task<IndexEntry> AskUserToSelectEntry(string query) | ||
{ | ||
var entries = await this.passwordManager.GetAllByNameAsync(query); | ||
if (!entries.Any()) | ||
{ | ||
return null; | ||
} | ||
|
||
var selectionPrompt = new SelectionPrompt<string>() | ||
.Title("Select entry:") | ||
.PageSize(10) | ||
.MoreChoicesText("[grey](Move up and down to reveal more password entries)[/]") | ||
.AddChoices(entries.Select(e => e.Name).ToArray()); | ||
var selectedEntryName = AnsiConsole.Prompt(selectionPrompt); | ||
|
||
return entries.Single(e => e.Name.Equals(selectedEntryName)); | ||
} | ||
} | ||
|
||
public abstract class BasePasswordAsyncCommand : AsyncCommand | ||
{ | ||
protected readonly IPasswordManager passwordManager; | ||
|
||
protected BasePasswordAsyncCommand(IPasswordManager passwordManager) | ||
{ | ||
this.passwordManager = passwordManager; | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
using PassManager.Core.Repository; | ||
using PassManager.Core.VirtualDirectory; | ||
using Spectre.Console.Cli; | ||
|
||
namespace PassManager.Console.Commands | ||
{ | ||
public abstract class BasePasswordCommand : Command | ||
{ | ||
protected readonly IPasswordManager passwordManager; | ||
|
||
public BasePasswordCommand(IPasswordManager passwordManager) | ||
{ | ||
this.passwordManager = passwordManager; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
using PassManager.Console.Commands.Settings; | ||
using PassManager.Console.Extensions; | ||
using PassManager.Core.Repository; | ||
using Spectre.Console; | ||
using Spectre.Console.Cli; | ||
using System.Threading.Tasks; | ||
|
||
namespace PassManager.Console.Commands | ||
{ | ||
public class DeletePasswordCommand : BasePasswordAsyncCommand<DeletePasswordSettings> | ||
{ | ||
public DeletePasswordCommand(IPasswordManager passwordManager) : base(passwordManager) | ||
{ | ||
} | ||
|
||
public override async Task<int> ExecuteAsync(CommandContext context, DeletePasswordSettings settings) | ||
{ | ||
var entry = await this.AskUserToSelectEntry(settings.Query); | ||
if (entry == null) | ||
{ | ||
AnsiConsole.MarkupLine($"[red]Provided query is invalid or password does not exist[/]"); | ||
return 0; | ||
} | ||
|
||
var result = await this.passwordManager.DeletePasswordByNameAsync(entry.Name); | ||
|
||
result.PrintConsoleErrorOrMessage("[green]Password deleted[/]"); | ||
|
||
return 0; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
using PassManager.Console.Commands.Settings; | ||
using PassManager.Console.Extensions; | ||
using PassManager.Core.Repository; | ||
using Spectre.Console; | ||
using Spectre.Console.Cli; | ||
using System.Threading.Tasks; | ||
|
||
namespace PassManager.Console.Commands | ||
{ | ||
public class DeleteSecretCommand : BasePasswordAsyncCommand<DeletePasswordSettings> | ||
{ | ||
public DeleteSecretCommand(IPasswordManager passwordManager) : base(passwordManager) | ||
{ | ||
} | ||
|
||
public override async Task<int> ExecuteAsync(CommandContext context, DeletePasswordSettings settings) | ||
{ | ||
var entry = await this.AskUserToSelectEntry(settings.Query); | ||
if (entry == null) | ||
{ | ||
AnsiConsole.MarkupLine("[red]Provided query is invalid or password does not exist[/]"); | ||
return 0; | ||
} | ||
|
||
if (!entry.HasCustomSecret) | ||
{ | ||
AnsiConsole.MarkupLine("[red]Selected entry is not locked by custom secret[/]"); | ||
return 0; | ||
} | ||
|
||
var secret = AnsiConsole.Prompt(new TextPrompt<string>("Enter [darkolivegreen2]secret[/] to unlock entry:").Secret()); | ||
var result = await this.passwordManager.DeleteSecret(entry.Name, secret); | ||
result.PrintConsoleErrorOrMessage("[green]Secret deleted. Password will be encrypted using default configuration[/]"); | ||
|
||
return 0; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
using PassManager.Console.Clipboard; | ||
using PassManager.Console.Commands.Settings; | ||
using PassManager.Console.Extensions; | ||
using PassManager.Core.Repository; | ||
using Spectre.Console; | ||
using Spectre.Console.Cli; | ||
using System.Threading.Tasks; | ||
|
||
namespace PassManager.Console.Commands | ||
{ | ||
public class GetPasswordCommand : BasePasswordAsyncCommand<DeletePasswordSettings> | ||
{ | ||
public GetPasswordCommand(IPasswordManager passwordManager) : base(passwordManager) | ||
{ | ||
} | ||
|
||
public override async Task<int> ExecuteAsync(CommandContext context, DeletePasswordSettings settings) | ||
{ | ||
var entry = await this.AskUserToSelectEntry(settings.Query); | ||
if (entry == null) | ||
{ | ||
AnsiConsole.MarkupLine("[red]Provided query is invalid or password does not exist[/]"); | ||
return 0; | ||
} | ||
|
||
string customSecret = null; | ||
if (entry.HasCustomSecret) | ||
{ | ||
var customSecretPrompt = new TextPrompt<string>("Enter [darkolivegreen2]secret[/]:").Secret(); | ||
customSecret = AnsiConsole.Prompt(customSecretPrompt); | ||
} | ||
|
||
var result = await this.passwordManager.GetPasswordAsync(entry.Name, customSecret); | ||
if (result.Success) | ||
{ | ||
WindowsClipboard.SetText(result.ExtensionData); | ||
} | ||
|
||
result.PrintConsoleErrorOrMessage("[green]Password copied to buffer[/]"); | ||
|
||
return 0; | ||
} | ||
} | ||
} |
Oops, something went wrong.