Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User interfaces for auth tokens #2266

Merged
merged 1 commit into from
Feb 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 175 additions & 0 deletions Cmdline/Action/AuthToken.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
using System;
using System.Collections.Generic;
using CommandLine;
using CommandLine.Text;
using log4net;

namespace CKAN.CmdLine
{
/// <summary>
/// Subcommand for managing authentication tokens
/// </summary>
public class AuthToken : ISubCommand
{
/// <summary>
/// Initialize the subcommand
/// </summary>
public AuthToken() { }

/// <summary>
/// Run the subcommand
/// </summary>
/// <param name="unparsed">Command line parameters not yet handled by parser</param>
/// <returns>
/// Exit code
/// </returns>
public int RunSubCommand(SubCommandOptions unparsed)
{
string[] args = unparsed.options.ToArray();
int exitCode = Exit.OK;

Parser.Default.ParseArgumentsStrict(args, new AuthTokenSubOptions(), (string option, object suboptions) =>
{
if (!string.IsNullOrEmpty(option) && suboptions != null)
{
CommonOptions options = (CommonOptions)suboptions;
user = new ConsoleUser(options.Headless);
manager = new KSPManager(user);
exitCode = options.Handle(manager, user);
if (exitCode == Exit.OK)
{
switch (option)
{
case "list":
exitCode = listAuthTokens(options);
break;
case "add":
exitCode = addAuthToken((AddAuthTokenOptions)options);
break;
case "remove":
exitCode = removeAuthToken((RemoveAuthTokenOptions)options);
break;
}
}
}
}, () => { exitCode = MainClass.AfterHelp(); });
return exitCode;
}

private int listAuthTokens(CommonOptions opts)
{
List<string> hosts = new List<string>(Win32Registry.GetAuthTokenHosts());
if (hosts.Count > 0)
{
int longestHostLen = hostHeader.Length;
int longestTokenLen = tokenHeader.Length;
foreach (string host in hosts)
{
longestHostLen = Math.Max(longestHostLen, host.Length);
string token;
if (Win32Registry.TryGetAuthToken(host, out token))
{
longestTokenLen = Math.Max(longestTokenLen, token.Length);
}
}
// Create format string: {0,-longestHostLen} {1,-longestTokenLen}
string fmt = string.Format("{0}0,-{2}{1} {0}1,-{3}{1}",
"{", "}", longestHostLen, longestTokenLen);
user.RaiseMessage(fmt, hostHeader, tokenHeader);
user.RaiseMessage(fmt,
new string('-', longestHostLen),
new string('-', longestTokenLen)
);
foreach (string host in hosts)
{
string token;
if (Win32Registry.TryGetAuthToken(host, out token))
{
user.RaiseMessage(fmt, host, token);
}
}
}
return Exit.OK;
}

private int addAuthToken(AddAuthTokenOptions opts)
{
if (Uri.CheckHostName(opts.host) != UriHostNameType.Unknown)
{
Win32Registry.SetAuthToken(opts.host, opts.token);
}
else
{
user.RaiseError("Invalid host name: {0}", opts.host);
}
return Exit.OK;
}

private int removeAuthToken(RemoveAuthTokenOptions opts)
{
Win32Registry.SetAuthToken(opts.host, null);
return Exit.OK;
}

private const string hostHeader = "Host";
private const string tokenHeader = "Token";

private IUser user;
private KSPManager manager;
private static readonly ILog log = LogManager.GetLogger(typeof(AuthToken));
}

internal class AuthTokenSubOptions : VerbCommandOptions
{
[VerbOption("list", HelpText = "List auth tokens")]
public CommonOptions ListOptions { get; set; }

[VerbOption("add", HelpText = "Add an auth token")]
public AddAuthTokenOptions AddOptions { get; set; }

[VerbOption("remove", HelpText = "Delete an auth token")]
public RemoveAuthTokenOptions RemoveOptions { get; set; }

[HelpVerbOption]
public string GetUsage(string verb)
{
HelpText ht = HelpText.AutoBuild(this, verb);
// Add a usage prefix line
ht.AddPreOptionsLine(" ");
if (string.IsNullOrEmpty(verb))
{
ht.AddPreOptionsLine("ckan authtoken - Manage authentication tokens");
ht.AddPreOptionsLine($"Usage: ckan authtoken <command> [options]");
}
else
{
ht.AddPreOptionsLine("authtoken " + verb + " - " + GetDescription(verb));
switch (verb)
{
case "add":
ht.AddPreOptionsLine($"Usage: ckan authtoken {verb} [options] host token");
break;
case "remove":
ht.AddPreOptionsLine($"Usage: ckan authtoken {verb} [options] host");
break;
case "list":
ht.AddPreOptionsLine($"Usage: ckan authtoken {verb} [options]");
break;
}
}
return ht;
}
}

internal class AddAuthTokenOptions : CommonOptions
{
[ValueOption(0)] public string host { get; set; }
[ValueOption(1)] public string token { get; set; }
}

internal class RemoveAuthTokenOptions : CommonOptions
{
[ValueOption(0)] public string host { get; set; }
}

}
1 change: 1 addition & 0 deletions Cmdline/CKAN-cmdline.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
<Compile Include="..\GlobalAssemblyInfo.cs">
<Link>Properties\GlobalAssemblyInfo.cs</Link>
</Compile>
<Compile Include="Action\AuthToken.cs" />
<Compile Include="Action\Available.cs" />
<Compile Include="Action\Compare.cs" />
<Compile Include="Action\CompatSubCommand.cs" />
Expand Down
15 changes: 7 additions & 8 deletions Cmdline/Main.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,20 +63,19 @@ public static int Main(string[] args)
switch (args[0])
{
case "repair":
var repair = new Repair();
return repair.RunSubCommand(new SubCommandOptions(args));
return (new Repair()).RunSubCommand(new SubCommandOptions(args));

case "ksp":
var ksp = new KSP();
return ksp.RunSubCommand(new SubCommandOptions(args));
return (new KSP()).RunSubCommand(new SubCommandOptions(args));

case "compat":
var compat = new CompatSubCommand();
return compat.RunSubCommand(new SubCommandOptions(args));
return (new CompatSubCommand()).RunSubCommand(new SubCommandOptions(args));

case "repo":
var repo = new Repo();
return repo.RunSubCommand(new SubCommandOptions(args));
return (new Repo()).RunSubCommand(new SubCommandOptions(args));

case "authtoken":
return (new AuthToken()).RunSubCommand(new SubCommandOptions(args));
}
}
catch (NoGameInstanceKraken)
Expand Down
3 changes: 3 additions & 0 deletions Cmdline/Options.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ internal class Actions : VerbCommandOptions
[VerbOption("ksp", HelpText = "Manage KSP installs")]
public SubCommandOptions KSP { get; set; }

[VerbOption("authtoken", HelpText = "Manage authentication tokens")]
public AuthTokenSubOptions AuthToken { get; set; }

[VerbOption("compat", HelpText = "Manage KSP version compatibility")]
public SubCommandOptions Compat { get; set; }

Expand Down
86 changes: 86 additions & 0 deletions ConsoleUI/AuthTokenAddDialog.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using System;
using CKAN.ConsoleUI.Toolkit;

namespace CKAN.ConsoleUI {

/// <summary>
/// Popup for adding a new authentication token.
/// </summary>
public class AuthTokenAddDialog : ConsoleDialog {

/// <summary>
/// Initialize the popup.
/// </summary>
public AuthTokenAddDialog() : base()
{
CenterHeader = () => "Create Authentication Key";

int top = (Console.WindowHeight - height) / 2;
SetDimensions(6, top, -6, top + height - 1);

int l = GetLeft(),
r = GetRight(),
t = GetTop(),
b = GetBottom();

AddObject(new ConsoleLabel(
l + 2, t + 2, l + 2 + labelW,
() => "Host:",
() => ConsoleTheme.Current.PopupBg,
() => ConsoleTheme.Current.PopupFg
));

hostEntry = new ConsoleField(
l + 2 + labelW + wPad, t + 2, r - 3
) {
GhostText = () => "<Enter a host name>"
};
AddObject(hostEntry);

AddObject(new ConsoleLabel(
l + 2, t + 4, l + 2 + labelW,
() => "Token:",
() => ConsoleTheme.Current.PopupBg,
() => ConsoleTheme.Current.PopupFg
));

tokenEntry = new ConsoleField(
l + 2 + labelW + wPad, t + 4, r - 3
) {
GhostText = () => "<Enter an authentication token>"
};
AddObject(tokenEntry);

AddTip("Esc", "Cancel");
AddBinding(Keys.Escape, (object sender) => false);

AddTip("Enter", "Accept", validKey);
AddBinding(Keys.Enter, (object sender) => {
if (validKey()) {
Win32Registry.SetAuthToken(hostEntry.Value, tokenEntry.Value);
return false;
} else {
// Don't close window on Enter unless adding a key
return true;
}
});
}

private bool validKey()
{
string token;
return hostEntry.Value.Length > 0
&& tokenEntry.Value.Length > 0
&& Uri.CheckHostName(hostEntry.Value) != UriHostNameType.Unknown
&& !Win32Registry.TryGetAuthToken(hostEntry.Value, out token);
}

private ConsoleField hostEntry;
private ConsoleField tokenEntry;

private const int wPad = 2;
private const int labelW = 6;
private const int height = 7;
}

}
Loading