Skip to content
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
2 changes: 2 additions & 0 deletions QRCoder/QRCodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,8 @@ public static QRCodeData GenerateMicroQrCode(string plainText, ECCLevel eccLevel
ValidateECCLevel(eccLevel);
if (eccLevel == ECCLevel.H)
throw new ArgumentOutOfRangeException(nameof(eccLevel), eccLevel, "Micro QR codes does not support error correction level H.");
if (eccLevel == ECCLevel.Q && requestedVersion == 0)
requestedVersion = -4; // If Q level is specified without a version, automatically select M4 since Q is only supported on M4
if (eccLevel == ECCLevel.Q && requestedVersion != -4)
throw new ArgumentOutOfRangeException(nameof(eccLevel), eccLevel, "Micro QR codes only supports error correction level Q for version M4.");
if (eccLevel != ECCLevel.Default && requestedVersion == -1)
Expand Down
248 changes: 248 additions & 0 deletions QRCoderTests/PayloadGeneratorTests/OneTimePasswordTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -237,4 +237,252 @@ public void one_time_password_generator_totp_default_algorithm_not_included()

pg.ToString().ShouldBe("otpauth://totp/Google:test%40google.com?secret=pwq65q55&issuer=Google");
}

[Fact]
public void one_time_password_generator_should_throw_when_secret_is_null()
{
var pg = new PayloadGenerator.OneTimePassword
{
Secret = null!,
Issuer = "Google",
Label = "test@google.com",
};

Should.Throw<InvalidOperationException>(() => pg.ToString())
.Message.ShouldBe("Secret must be a filled out base32 encoded string");
}

[Fact]
public void one_time_password_generator_should_throw_when_secret_is_empty()
{
var pg = new PayloadGenerator.OneTimePassword
{
Secret = "",
Issuer = "Google",
Label = "test@google.com",
};

Should.Throw<InvalidOperationException>(() => pg.ToString())
.Message.ShouldBe("Secret must be a filled out base32 encoded string");
}

[Fact]
public void one_time_password_generator_should_throw_when_secret_is_whitespace()
{
var pg = new PayloadGenerator.OneTimePassword
{
Secret = " ",
Issuer = "Google",
Label = "test@google.com",
};

Should.Throw<InvalidOperationException>(() => pg.ToString())
.Message.ShouldBe("Secret must be a filled out base32 encoded string");
}

[Fact]
public void one_time_password_generator_should_throw_when_issuer_contains_colon()
{
var pg = new PayloadGenerator.OneTimePassword
{
Secret = "pwq6 5q55",
Issuer = "Google:Company",
Label = "test@google.com",
};

Should.Throw<InvalidOperationException>(() => pg.ToString())
.Message.ShouldBe("Issuer must not have a ':'");
}

[Fact]
public void one_time_password_generator_should_throw_when_label_contains_colon()
{
var pg = new PayloadGenerator.OneTimePassword
{
Secret = "pwq6 5q55",
Issuer = "Google",
Label = "test:user@google.com",
};

Should.Throw<InvalidOperationException>(() => pg.ToString())
.Message.ShouldBe("Label must not have a ':'");
}

[Fact]
public void one_time_password_generator_totp_should_throw_when_period_is_null()
{
var pg = new PayloadGenerator.OneTimePassword
{
Secret = "pwq6 5q55",
Issuer = "Google",
Label = "test@google.com",
Period = null,
};

Should.Throw<InvalidOperationException>(() => pg.ToString())
.Message.ShouldBe("Period must be set when using OneTimePasswordAuthType.TOTP");
}

[Fact]
public void one_time_password_generator_totp_with_only_issuer()
{
var pg = new PayloadGenerator.OneTimePassword
{
Secret = "pwq6 5q55",
Issuer = "Google",
};

pg.ToString().ShouldBe("otpauth://totp/Google?secret=pwq65q55&issuer=Google");
}

[Fact]
public void one_time_password_generator_hotp_with_only_issuer()
{
var pg = new PayloadGenerator.OneTimePassword
{
Secret = "pwq6 5q55",
Issuer = "Google",
Type = PayloadGenerator.OneTimePassword.OneTimePasswordAuthType.HOTP,
Counter = 100,
};

pg.ToString().ShouldBe("otpauth://hotp/Google?secret=pwq65q55&issuer=Google&counter=100");
}

[Fact]
public void one_time_password_generator_totp_with_no_issuer_or_label()
{
var pg = new PayloadGenerator.OneTimePassword
{
Secret = "pwq6 5q55",
};

pg.ToString().ShouldBe("otpauth://totp/?secret=pwq65q55");
}

[Fact]
public void one_time_password_generator_hotp_with_no_issuer_or_label()
{
var pg = new PayloadGenerator.OneTimePassword
{
Secret = "pwq6 5q55",
Type = PayloadGenerator.OneTimePassword.OneTimePasswordAuthType.HOTP,
Counter = 50,
};

pg.ToString().ShouldBe("otpauth://hotp/?secret=pwq65q55&counter=50");
}

[Fact]
public void one_time_password_generator_hotp_with_zero_counter()
{
var pg = new PayloadGenerator.OneTimePassword
{
Secret = "pwq6 5q55",
Issuer = "Google",
Label = "test@google.com",
Type = PayloadGenerator.OneTimePassword.OneTimePasswordAuthType.HOTP,
Counter = 0,
};

pg.ToString().ShouldBe("otpauth://hotp/Google:test%40google.com?secret=pwq65q55&issuer=Google&counter=0");
}

[Fact]
public void one_time_password_generator_hotp_with_sha512_algorithm()
{
var pg = new PayloadGenerator.OneTimePassword
{
Secret = "pwq6 5q55",
Issuer = "Google",
Label = "test@google.com",
Type = PayloadGenerator.OneTimePassword.OneTimePasswordAuthType.HOTP,
Counter = 200,
AuthAlgorithm = PayloadGenerator.OneTimePassword.OneTimePasswordAuthAlgorithm.SHA512,
};

pg.ToString().ShouldBe("otpauth://hotp/Google:test%40google.com?secret=pwq65q55&issuer=Google&algorithm=SHA512&counter=200");
}

[Fact]
public void one_time_password_generator_should_strip_spaces_from_secret()
{
var pg = new PayloadGenerator.OneTimePassword
{
Secret = "pwq6 5q55 abcd efgh",
Issuer = "Google",
Label = "test@google.com",
};

pg.ToString().ShouldBe("otpauth://totp/Google:test%40google.com?secret=pwq65q55abcdefgh&issuer=Google");
}

[Fact]
public void one_time_password_generator_totp_with_special_characters_in_label()
{
var pg = new PayloadGenerator.OneTimePassword
{
Secret = "pwq6 5q55",
Issuer = "Google",
Label = "test+user@google.com",
};

pg.ToString().ShouldBe("otpauth://totp/Google:test%2Buser%40google.com?secret=pwq65q55&issuer=Google");
}

[Fact]
public void one_time_password_generator_totp_with_special_characters_in_issuer()
{
var pg = new PayloadGenerator.OneTimePassword
{
Secret = "pwq6 5q55",
Issuer = "Google & Company",
Label = "test@google.com",
};

pg.ToString().ShouldBe("otpauth://totp/Google%20%26%20Company:test%40google.com?secret=pwq65q55&issuer=Google%20%26%20Company");
}

[Fact]
public void one_time_password_generator_hotp_with_large_counter()
{
var pg = new PayloadGenerator.OneTimePassword
{
Secret = "pwq6 5q55",
Issuer = "Google",
Label = "test@google.com",
Type = PayloadGenerator.OneTimePassword.OneTimePasswordAuthType.HOTP,
Counter = 999999999,
};

pg.ToString().ShouldBe("otpauth://hotp/Google:test%40google.com?secret=pwq65q55&issuer=Google&counter=999999999");
}

[Fact]
public void one_time_password_generator_totp_with_large_period()
{
var pg = new PayloadGenerator.OneTimePassword
{
Secret = "pwq6 5q55",
Issuer = "Google",
Label = "test@google.com",
Period = 3600,
};

pg.ToString().ShouldBe("otpauth://totp/Google:test%40google.com?secret=pwq65q55&issuer=Google&period=3600");
}

[Fact]
public void one_time_password_generator_totp_with_large_digits()
{
var pg = new PayloadGenerator.OneTimePassword
{
Secret = "pwq6 5q55",
Issuer = "Google",
Label = "test@google.com",
Digits = 10,
};

pg.ToString().ShouldBe("otpauth://totp/Google:test%40google.com?secret=pwq65q55&issuer=Google&digits=10");
}
}
Loading