require "test_helper" class MagicLinkTest < ActiveSupport::TestCase test "stores only digests and redeems once, creating the user" do link = MagicLink.issue!(email: " New@Example.com ") assert_equal "new@example.com", link.email assert_not_equal link.token, link.token_digest assert_equal link, MagicLink.find_by_token(link.token) user = link.redeem! assert_equal "new@example.com", user.email assert_nil MagicLink.find_by_token(link.token), "used" end test "expires" do link = MagicLink.issue!(email: "a@example.com") travel MagicLink::LOGIN_TTL + 1.second do assert_nil MagicLink.find_by_token(link.token) end end test "code: wrong attempts burn the link" do link = MagicLink.issue!(email: "a@example.com") wrong = link.code == "000000" ? "111111" : "000000" MagicLink::MAX_CODE_ATTEMPTS.times { assert_nil MagicLink.find_by_code("a@example.com", wrong) } assert_nil MagicLink.find_by_code("a@example.com", link.code) end test "code accepts formatting and the right email only" do link = MagicLink.issue!(email: "a@example.com") assert_equal link, MagicLink.find_by_code("A@example.com", link.code.chars.each_slice(3).map(&:join).join(" ")) assert_nil MagicLink.find_by_code("b@example.com", link.code) end test "return_to only allows local paths" do assert_equal "/d/abc", MagicLink.safe_path("/d/abc") assert_nil MagicLink.safe_path("https://evil.example") assert_nil MagicLink.safe_path("//evil.example") end test "invitation grants the document on redeem" do owner = create_user("owner@example.com") doc = create_document(owner) link = MagicLink.issue!(email: "guest@example.com", purpose: :invitation, document: doc, role: :editor, invited_by: owner) user = link.redeem! assert_equal :editor, doc.role_for(user:) assert_equal "/d/#{doc.id}", link.destination end end