defmodule Mix.Tasks.Totp.TimeCheck do @shortdoc "Check server time and TOTP time synchronization" @moduledoc """ Diagnostic tool to check if the server's clock is correct. Usage: mix totp.time_check This will: 1. Show the server's current time (BEAM VM time) 2. Show the system's current time 3. Calculate what TOTP codes should be valid right now for a test secret """ use Mix.Task require Logger def run(_args) do Mix.Task.run("app.start") IO.puts("\n=== Time Synchronization Check ===\n") # Get different time sources system_time = System.system_time(:second) os_time = :os.system_time(:second) datetime_now = DateTime.utc_now() IO.puts("System.system_time(:second): #{system_time}") IO.puts(" → #{DateTime.from_unix!(system_time)}") IO.puts("") IO.puts(":os.system_time(:second): #{os_time}") IO.puts(" → #{DateTime.from_unix!(os_time)}") IO.puts("") IO.puts("DateTime.utc_now(): #{datetime_now}") IO.puts(" → unix: #{DateTime.to_unix(datetime_now)}") IO.puts("") # Check if they match if system_time == os_time and system_time == DateTime.to_unix(datetime_now) do IO.puts("✓ All time sources agree") else IO.puts("⚠️ WARNING: Time sources disagree!") IO.puts(" System vs OS diff: #{system_time - os_time} seconds") IO.puts(" System vs DateTime diff: #{system_time - DateTime.to_unix(datetime_now)} seconds") end IO.puts("") # Show what TOTP codes would be generated now test_secret = NimbleTOTP.secret() current_code = NimbleTOTP.verification_code(test_secret, time: system_time) prev_code = NimbleTOTP.verification_code(test_secret, time: system_time - 30) next_code = NimbleTOTP.verification_code(test_secret, time: system_time + 30) IO.puts("Test TOTP codes (with random secret):") IO.puts(" Current window: #{current_code}") IO.puts(" Previous (-30s): #{prev_code}") IO.puts(" Next (+30s): #{next_code}") IO.puts("") # Recommend action IO.puts("=== Recommendations ===") IO.puts("") IO.puts("Compare the server time above with actual UTC time:") IO.puts(" Current actual UTC: Run 'date -u' on your local machine") IO.puts("") IO.puts("If the server time is wrong:") IO.puts(" 1. Check K8s node time: kubectl exec -it -- date -u") IO.puts(" 2. Check if NTP is running on the node") IO.puts(" 3. Restart the pod to resync time") IO.puts("") end end