/// <summary> /// Generates several raw codes. This is used to account for counter drift across 2 generators. /// </summary> /// <param name="window"> /// Number of additional codes to generate in each direction. For example, a value of 2 will generate 5 codes: /// 2 after the current value, 2 before, and one for current value. Non-positive value will use defaults of 1 /// for TOTP, and 2 for HOTP. /// </param> /// <param name="groupSize">Optional. Maximum number of digits per digit group.</param> /// <returns>Enumerable of generated codes.</returns> public IEnumerable <string> GenerateWindow(int window = 0, int groupSize = 0) { if (window == 0) { window = this.Settings.Type switch { ChallengeType.Time => 1, ChallengeType.Counter => 2, _ => 0 } } ; var ctr = this.Settings.GetCounterValue(); for (var i = ctr - window; i <= ctr + window; i++) { var number = this.GenerateNumber(value: i); if (groupSize > 0) { yield return(StringCodeFormatter.FormatGroupped(number, this.Settings.Digits, groupSize)); } else { yield return(StringCodeFormatter.Format(number, this.Settings.Digits)); } } }
/// <summary> /// Generates one-time password. /// </summary> /// <param name="groupSize">Optional. Maximum number of digits per digit group.</param> /// <param name="offset">Counter offset to use when generating.</param> /// <returns>Generated password.</returns> public string Generate(int groupSize = 0, int offset = 0) { var number = this.GenerateNumber(offset); if (groupSize > 0) { return(StringCodeFormatter.FormatGroupped(number, this.Settings.Digits, groupSize)); } else { return(StringCodeFormatter.Format(number, this.Settings.Digits)); } }