这是一个完全由 AI 编写的小工具,用于生成 TOTP 密钥

<style>
/* Base styles for the TOTP container */
#totp {
  font-family: Arial, sans-serif;
  color: #333;
  box-shadow: 0 0 10px rgba(0,0,0,0.1);
  margin: 20px auto;
  padding: 20px;
  box-sizing: border-box;
  width: 100%;
  max-width: 600px;
}

/* Style for the labels - now bold */
label.totp {
  display: block;
  margin-top: 10px;
  margin-bottom: 5px;
  color: #555;
  font-weight: bold; /* Make the label text bold */
}

#totp input[type="text"],
#totp input[type="number"] {
  display: block;
  width: 100%; /* Adjust width to account for padding and border */
  padding: 10px;
  margin-bottom: 10px; /* Add space below each input */
  border: 1px solid #ccc;
  border-radius: 4px;
  font-size: 16px;
  line-height: 1.5;
}

/* Progress bar and remaining time styles */
.content {
  margin-top: 20px;
}

.has-text-grey {
  display: block;
  color: #666;
}

/* Box for the TOTP token */
.box {
  text-align: center;
  margin-top: 20px;
  border: solid 1px #dbe2e8;
  background: #f7f9fc;
  display: flex; /* Use flexbox to center the content */
  justify-content: center; /* Center horizontally */
  align-items: center; /* Center vertically */
  padding: 0; /* Reset padding */
}

/* Style for the token text - ensures it is centered and bold */
#token {
  font-size: 3rem; /* Increased font size for the token */
  font-weight: bold; /* Makes the token text bold */
  margin: 0; /* Reset margin */
  word-break: break-all;
  flex: 0 0 auto; /* Do not grow or shrink */
}

.title {
  font-size: 2rem;
  margin: 0;
  word-break: break-all;
}


/* Base styles for the progress bar */
.progress {
  width: 100%;
  height: 15px;
  border-radius: 5px;
  overflow: hidden;
}
.progress.is-info::-webkit-progress-value {
  background-color: #00d1b2; /* 绿色 */
}

.progress.is-warning::-webkit-progress-value {
  background-color: #ffc107; /* 黄色 */
}

.progress.is-danger::-webkit-progress-value {
  background-color: #ff3860; /* 红色 */
}

.progress.is-info::-moz-progress-bar {
  background-color: #00d1b2; /* 绿色 */
}

.progress.is-warning::-moz-progress-bar {
  background-color: #ffc107; /* 黄色 */
}

.progress.is-danger::-moz-progress-bar {
  background-color: #ff3860; /* 红色 */
}

.has-text-grey {
  color: #4a4a4a; /* Original color */
}

.has-text-warning {
  color: #ffc107; /* Yellow color */
}

.has-text-danger {
  color: #ff3860; /* Red color */
}

</style>


<div id="totp">
  <label for="secret" class="totp">Secret Key:</label>
  <input type="text" id="secret" placeholder="Enter your secret key" oninput="generateTOTP()">
  
  <label for="period" class="totp">Period in seconds:</label>
  <input type="number" id="period" placeholder="Enter period in seconds" value="30" oninput="generateTOTP()">
  
  <label for="digits" class="totp">Number of digits:</label>
  <input type="number" id="digits" placeholder="Enter number of digits" value="6" oninput="generateTOTP()">
  
<div class="content"><span class="has-text-grey is-size-7"></span><progress class="progress is-info" max="30" value="3"></progress></div>

<div class="box"><p class="title is-size-1 has-text-centered" id="token"></p></div>

</div>

<script src="https://unpkg.com/otpauth@9.2.4/dist/otpauth.umd.min.js"></script>

<script>
  var countdown;
  var countdownInterval;

  function updateProgressBarAndSpan(maxValue, remaining) {
    var progressBar = document.querySelector('.progress');
    
    var remainingTimeSpan = document.querySelector('.is-size-7');
    

  // 重置进度条和文本颜色
  progressBar.classList.remove('is-info', 'is-warning', 'is-danger');
  remainingTimeSpan.classList.remove('has-text-warning', 'has-text-danger');
    // Change class based on remaining time
    if (remaining < 5) {
      progressBar.classList.add('is-danger');
      remainingTimeSpan.classList.add('has-text-grey', 'has-text-danger');
    } else if (remaining < 10) {
      progressBar.classList.add('is-warning');
      remainingTimeSpan.classList.add('has-text-grey', 'has-text-warning');
    }
    progressBar.max = maxValue;
    progressBar.value = remaining;
    remainingTimeSpan.innerText = 'Remaining time: ' + remaining + 's';
  }


  function generateTOTP() {
    clearTimeout(countdown);
    clearInterval(countdownInterval);

    var secret = document.getElementById('secret').value;
    var period = parseInt(document.getElementById('period').value) || 30;
    var digits = parseInt(document.getElementById('digits').value) || 6;

    var totp = new OTPAuth.TOTP({
      secret: OTPAuth.Secret.fromBase32(secret),
      digits: digits,
      period: period,
      algorithm: 'SHA1'
    });

    var totpCode = totp.generate();
    document.getElementById('token').innerText = totpCode;

    var remainingTime = period - Math.floor((Date.now() / 1000) % period);
    updateProgressBarAndSpan(period, remainingTime);

    countdownInterval = setInterval(function() {
      remainingTime--;
      if (remainingTime < 0) {
        remainingTime = period;
      }
      updateProgressBarAndSpan(period, remainingTime);
    }, 1000);

    countdown = setTimeout(generateTOTP, remainingTime * 1000);
  }
  
  // Call generateTOTP once on page load to initialize
  generateTOTP();

</script>