blob: 045151b9b7637554e6cbdf8a410a46793fa44750 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/sms/sms_parser.h"
#include "base/optional.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
#include "url/origin.h"
namespace content {
namespace {
url::Origin ParseOrigin(const std::string& message) {
base::Optional<SmsParser::Result> result = SmsParser::Parse(message);
return result->origin;
}
std::string ParseOTP(const std::string& message) {
base::Optional<SmsParser::Result> result = SmsParser::Parse(message);
return result->one_time_code;
}
} // namespace
TEST(SmsParserTest, NoToken) {
ASSERT_FALSE(SmsParser::Parse("foo"));
}
TEST(SmsParserTest, WithTokenInvalidUrl) {
ASSERT_FALSE(SmsParser::Parse("For: foo"));
}
TEST(SmsParserTest, NoSpace) {
ASSERT_FALSE(SmsParser::Parse("To:https://example.com"));
}
TEST(SmsParserTest, InvalidUrl) {
ASSERT_FALSE(SmsParser::Parse("For: //example.com"));
}
TEST(SmsParserTest, FtpScheme) {
ASSERT_FALSE(SmsParser::Parse("For: ftp://example.com"));
}
TEST(SmsParserTest, HttpScheme) {
ASSERT_FALSE(SmsParser::Parse("For: http://example.com"));
}
TEST(SmsParserTest, Mailto) {
ASSERT_FALSE(SmsParser::Parse("For: mailto:goto@chromium.org"));
}
TEST(SmsParserTest, MissingOneTimeCodeParameter) {
ASSERT_FALSE(SmsParser::Parse("For: https://example.com"));
}
TEST(SmsParserTest, Basic) {
ASSERT_EQ(url::Origin::Create(GURL("https://example.com")),
ParseOrigin("For: https://example.com?otp=123"));
}
TEST(SmsParserTest, Realistic) {
ASSERT_EQ(url::Origin::Create(GURL("https://example.com")),
ParseOrigin("<#> Your OTP is 1234ABC.\nFor: "
"https://example.com?otp=123&s3LhKBB0M33"));
}
TEST(SmsParserTest, OneTimeCode) {
auto result = SmsParser::Parse("For: https://example.com?otp=123");
ASSERT_EQ("123", (*result).one_time_code);
}
TEST(SmsParserTest, LocalhostForDevelopment) {
ASSERT_EQ(url::Origin::Create(GURL("http://localhost:8080")),
ParseOrigin("For: http://localhost:8080?otp=123"));
ASSERT_EQ(url::Origin::Create(GURL("http://localhost:80")),
ParseOrigin("For: http://localhost:80?otp=123"));
ASSERT_EQ(url::Origin::Create(GURL("http://localhost")),
ParseOrigin("For: http://localhost?otp=123"));
ASSERT_FALSE(SmsParser::Parse("For: localhost"));
}
TEST(SmsParserTest, Paths) {
ASSERT_EQ(url::Origin::Create(GURL("https://example.com")),
ParseOrigin("For: https://example.com/foobar?otp=123"));
}
TEST(SmsParserTest, Message) {
ASSERT_EQ(url::Origin::Create(GURL("https://example.com")),
ParseOrigin("hello world\nFor: https://example.com?otp=123"));
}
TEST(SmsParserTest, Whitespace) {
ASSERT_EQ(url::Origin::Create(GURL("https://example.com")),
ParseOrigin("hello world\nFor: https://example.com?otp=123 "));
}
TEST(SmsParserTest, Newlines) {
ASSERT_EQ(url::Origin::Create(GURL("https://example.com")),
ParseOrigin("hello world\nFor: https://example.com?otp=123\n"));
}
TEST(SmsParserTest, TwoTokens) {
ASSERT_EQ(url::Origin::Create(GURL("https://b.com")),
ParseOrigin("For: https://a.com For: https://b.com?otp=123"));
}
TEST(SmsParserTest, DifferentPorts) {
ASSERT_NE(url::Origin::Create(GURL("https://a.com")),
ParseOrigin("For: https://a.com:8443/?otp=123"));
ASSERT_NE(url::Origin::Create(GURL("https://a.com:443")),
ParseOrigin("For: https://a.com:8443/?otp=123"));
}
TEST(SmsParserTest, ImplicitPort) {
ASSERT_EQ(url::Origin::Create(GURL("https://a.com")),
ParseOrigin("For: https://a.com:443/?otp=123"));
ASSERT_NE(url::Origin::Create(GURL("https://a.com")),
ParseOrigin("For: https://a.com:8443/?otp=123"));
}
TEST(SmsParserTest, Redirector) {
ASSERT_EQ(url::Origin::Create(GURL("https://a.com")),
ParseOrigin("For: https://a.com/redirect?otp=123&https://b.com"));
ASSERT_EQ(
url::Origin::Create(GURL("https://a.com")),
ParseOrigin("For: https://a.com/redirect?&otp=123&https:%2f%2fb.com"));
ASSERT_EQ(
url::Origin::Create(GURL("https://a.com")),
ParseOrigin("For: https://a.com/redirect?otp=123#https:%2f%2fb.com"));
}
TEST(SmsParserTest, UsernameAndPassword) {
ASSERT_EQ(url::Origin::Create(GURL("https://a.com")),
ParseOrigin("For: https://b.com@a.com/?otp=123"));
ASSERT_EQ(url::Origin::Create(GURL("https://a.com")),
ParseOrigin("For: https://b.com:c.com@a.com/?otp=123"));
ASSERT_EQ(url::Origin::Create(GURL("https://a.com")),
ParseOrigin("For: https://b.com:noodle@a.com:443/?otp=123"));
}
TEST(SmsParserTest, HarmlessOriginsButInvalid) {
ASSERT_FALSE(SmsParser::Parse("For: data://123"));
}
TEST(SmsParserTest, AppHash) {
ASSERT_EQ(
url::Origin::Create(GURL("https://example.com")),
ParseOrigin(
"<#> Hello World\nFor: https://example.com?otp=123&s3LhKBB0M33"));
}
TEST(SmsParserTest, OneTimeCodeCharRanges) {
ASSERT_EQ("cannot-contain-hashes",
ParseOTP("For: https://example.com?otp=cannot-contain-hashes#yes"));
ASSERT_EQ(
"can-contain-numbers-like-123",
ParseOTP("For: https://example.com?otp=can-contain-numbers-like-123"));
ASSERT_EQ(
"can-contain-utf8-like-🤷",
ParseOTP("For: https://example.com?otp=can-contain-utf8-like-🤷"));
ASSERT_EQ(
"can-contain-chars-like-*^$@",
ParseOTP("For: https://example.com?otp=can-contain-chars-like-*^$@"));
ASSERT_EQ(
"human-readable-words-like-sillyface",
ParseOTP(
"For: https://example.com?otp=human-readable-words-like-sillyface"));
ASSERT_EQ(
"works-with-more-params",
ParseOTP("For: https://example.com?otp=works-with-more-params&foo=bar"));
ASSERT_EQ(
"works-with-more-params",
ParseOTP("For: https://example.com?foo=bar&otp=works-with-more-params"));
ASSERT_EQ(
"can-it-be-super-lengthy-like-a-lot",
ParseOTP(
"For: https://example.com?otp=can-it-be-super-lengthy-like-a-lot"));
}
} // namespace content