コード例 #1
0
        public virtual Task <bool> WaitForTwoFactorCode(ITwoFactorChannelInfo[] channels, CancellationToken token)
        {
            var twoFactorTask = new TaskCompletionSource <bool>();

            Task.Run(async() =>
            {
                var cancelCallback  = token.Register(() => { twoFactorTask.SetResult(true); });
                var pushChannelInfo = new Dictionary <TwoFactorPushAction, ITwoFactorPushInfo>();
                var codeChannelInfo = new Dictionary <TwoFactorChannel, ITwoFactorAppCodeInfo>();
                ITwoFactorAppCodeInfo codeChannel = null;
                {
                    foreach (var ch in channels)
                    {
                        if (ch is ITwoFactorPushInfo pi)
                        {
                            if (pi.SupportedActions == null)
                            {
                                continue;
                            }
                            foreach (var a in pi.SupportedActions)
                            {
                                if (pushChannelInfo.ContainsKey(a))
                                {
                                    continue;
                                }
                                pushChannelInfo.Add(a, pi);
                            }
                        }

                        if (ch is ITwoFactorAppCodeInfo aci)
                        {
                            if (codeChannel == null)
                            {
                                codeChannel = aci;
                            }

                            aci.Duration = TwoFactorDuration.Every30Days;

                            if (codeChannelInfo.ContainsKey(ch.Channel))
                            {
                                continue;
                            }
                            codeChannelInfo.Add(ch.Channel, aci);
                        }
                    }
                }

                var info = pushChannelInfo.Keys
                           .Select(x => x.GetPushActionText())
                           .Where(x => !string.IsNullOrEmpty(x))
                           .Select(x => $"\"{x}\"")
                           .ToList();
                if (codeChannelInfo.Count > 1)
                {
                    var codes = string.Join(", ", codeChannelInfo.Values.Select(x => x.ChannelName));
                    info.Add($"To switch between app code channels: code=<channel> where channels are {codes}");
                }

                Console.WriteLine("To change default 2FA token persistence use command 2fa=<duration>");
                var dur = Enum
                          .GetValues(typeof(TwoFactorDuration))
                          .OfType <TwoFactorDuration>()
                          .Select(x => $"\"{DurationToText(x)}\"")
                          .ToArray();
                Console.WriteLine("Available durations are: " + string.Join(", ", dur));

                info.Add("<Enter> to Cancel");

                Console.WriteLine("\nTwo Factor Authentication");
                Console.WriteLine(string.Join("\n", info));
                while (true)
                {
                    if (codeChannel != null)
                    {
                        Console.Write($"[{codeChannel.ChannelName ?? ""}] ({DurationToText(codeChannel.Duration)})");
                    }

                    Console.Write(" > ");

                    var code = await InputManager.ReadLine();

                    if (twoFactorTask.Task.IsCompleted)
                    {
                        break;
                    }
                    if (string.IsNullOrEmpty(code))
                    {
                        twoFactorTask.TrySetResult(false);
                        break;
                    }

                    if (code.StartsWith("code="))
                    {
                        var ch  = code.Substring(5);
                        var cha = codeChannelInfo.Values
                                  .FirstOrDefault(x => x.ChannelName == ch.ToLowerInvariant());
                        if (cha != null)
                        {
                            codeChannel = cha;
                        }
                        else
                        {
                            Console.WriteLine($"Invalid 2FA code channel: {ch}");
                        }

                        continue;
                    }


                    if (code.StartsWith("2fa="))
                    {
                        if (TryParseTextToDuration(code.Substring(4), out var duration))
                        {
                            if (codeChannel != null)
                            {
                                codeChannel.Duration = duration;
                            }
                        }

                        continue;
                    }

                    if (AuthUIExtensions.TryParsePushAction(code, out var action))
                    {
                        if (pushChannelInfo.ContainsKey(action))
                        {
                            await pushChannelInfo[action].InvokeTwoFactorPushAction(action);
                        }
                        else
                        {
                            Console.WriteLine($"Unsupported 2fa push action: {code}");
                        }

                        continue;
                    }

                    if (codeChannel != null)
                    {
                        try
                        {
                            await codeChannel.InvokeTwoFactorCodeAction(code);
                        }
                        catch (KeeperAuthFailed)
                        {
                            Console.WriteLine("Code is invalid");
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine(e.Message);
                        }
                    }
                }

                cancelCallback.Dispose();
            },
                     token);
            return(twoFactorTask.Task);
        }
コード例 #2
0
        private static async Task ProcessCommand(AuthSync auth, string command)
        {
            if (command == "?")
            {
                PrintStepHelp(auth.Step);
                return;
            }

            if (auth.Step is DeviceApprovalStep das)
            {
                if (command.StartsWith($"{ChannelCommand}=", StringComparison.InvariantCultureIgnoreCase))
                {
                    var channelText = command.Substring(ChannelCommand.Length + 1).ToLowerInvariant();
                    var channel     = das.Channels.FirstOrDefault(x => x.ChannelText() == channelText);
                    if (channel != default)
                    {
                        das.DefaultChannel = channel;
                    }
                    else
                    {
                        Console.WriteLine($"Device Approval push channel {channelText} not found.");
                    }
                }
                else if (string.Compare(command, PushCommand, StringComparison.InvariantCultureIgnoreCase) == 0)
                {
                    await das.SendPush(das.DefaultChannel);
                }
                else
                {
                    await das.SendCode(das.DefaultChannel, command);
                }
            }

            else if (auth.Step is TwoFactorStep tfs)
            {
                if (command.StartsWith($"{ChannelCommand}=", StringComparison.InvariantCultureIgnoreCase))
                {
                    var channelText = command.Substring(ChannelCommand.Length + 1).ToLowerInvariant();
                    var channel     = tfs.Channels.FirstOrDefault(x => x.ChannelText() == channelText);
                    if (channel != default)
                    {
                        tfs.DefaultChannel = channel;
                    }
                    else
                    {
                        Console.WriteLine($"2FA channel {channelText} not found.");
                    }
                }
                else if (command.StartsWith($"{ExpireCommand}=", StringComparison.InvariantCultureIgnoreCase))
                {
                    var expireText = command.Substring(ExpireCommand.Length + 1).ToLowerInvariant();
                    var duration   = Expires.FirstOrDefault(x => x.ExpireText() == expireText);
                    if (duration != default)
                    {
                        tfs.Duration = duration;
                    }
                }
                else
                {
                    var push = tfs.Channels
                               .SelectMany(x => tfs.GetChannelPushActions(x) ?? Enumerable.Empty <TwoFactorPushAction>())
                               .FirstOrDefault(x => x.GetPushActionText() == command);
                    if (push != default)
                    {
                        await tfs.SendPush(push);
                    }
                    else
                    {
                        await tfs.SendCode(tfs.DefaultChannel, command);
                    }
                }
            }
            else if (auth.Step is PasswordStep ps)
            {
                await ps.VerifyPassword(command);
            }
            else if (auth.Step is SsoTokenStep sts)
            {
                if (string.Compare(command, "password", StringComparison.InvariantCultureIgnoreCase) == 0)
                {
                    await sts.LoginWithPassword();
                }
                else
                {
                    await sts.SetSsoToken(command);
                }
            }
            else if (auth.Step is SsoDataKeyStep sdks)
            {
                if (AuthUIExtensions.TryParseDataKeyShareChannel(command, out var channel))
                {
                    await sdks.RequestDataKey(channel);
                }
                else
                {
                    Console.WriteLine($"Invalid data key share channel: {command}");
                }
            }
            else
            {
                Console.WriteLine($"Invalid command. Type \"?\" to list available commands.");
            }
        }