4位PIN穷举助手

by 孙 超

HTML

<div id="pin">0000</div>

<div id="count"></div>

<div>
  <button id="prevBtn">上一个</button>
  <button id="nextBtn">下一个(空格)</button>
</div>

<h3>随机生成记录</h3>
<div id="history"></div>

<h3>导入已试过数字</h3>

<textarea id="batchInput" placeholder="每行输入一个4位数字"></textarea>
<br />

<button id="importBtn">导入</button>

<div id="tip">按 空格 键切换下一个未试过的4位数字</div>

CSS

body {
    font-family: sans-serif;
    text-align: center;
    padding: 40px;
  }

  #pin {
    font-size: 90px;
    font-weight: bold;
    letter-spacing: 10px;
    margin-bottom: 10px;
  }

  #count {
    font-size: 18px;
    color: #666;
    margin-bottom: 20px;
  }

  #history {
    margin: 20px auto;
    width: 320px;
    text-align: left;
    border: 1px solid #ccc;
    padding: 10px;
    max-height: 220px;
    overflow-y: auto;
    font-family: monospace;
    background: #fafafa;
  }

  textarea {
    width: 320px;
    height: 180px;
    font-size: 16px;
    padding: 10px;
    margin-top: 20px;
  }

  button {
    margin-top: 10px;
    padding: 10px 20px;
    font-size: 16px;
    cursor: pointer;
  }

  #tip {
    margin-top: 30px;
    color: #999;
  }

JavaScript

/**
     * 已经尝试过的密码:
     * 1.日期 0101到1231
     * 2. 1900到2056
     * 3. 9800~9899,9900~9999
     * 
     * 
     * 
     */
const GENERATED_KEY = 'generatedPins';
const IMPORTED_KEY = 'importedPins';

let generatedPins = JSON.parse(
  localStorage.getItem(GENERATED_KEY) || '[]'
);

let importedPins = new Set(
  JSON.parse(localStorage.getItem(IMPORTED_KEY) || '[]')
);

let currentIndex = generatedPins.length - 1;

const pinEl = document.getElementById('pin');
const countEl = document.getElementById('count');
const historyEl = document.getElementById('history');
const batchInput = document.getElementById('batchInput');

function save() {
  localStorage.setItem(
    GENERATED_KEY,
    JSON.stringify(generatedPins)
  );

  localStorage.setItem(
    IMPORTED_KEY,
    JSON.stringify([...importedPins])
  );
}

function getAllTestedSet() {
  return new Set([
    ...generatedPins,
    ...importedPins
  ]);
}

function updateCount() {
  const total = getAllTestedSet().size;

  countEl.innerText =
    `总已尝试: ${total} / 10000
随机生成: ${generatedPins.length}
手动导入: ${importedPins.size}`;
}

function updateHistory() {
  historyEl.innerHTML =
    generatedPins
      .slice()
      .reverse()
      .map((v, i) => {
        const realIndex =
          generatedPins.length - 1 - i;

        const mark =
          realIndex === currentIndex
            ? '👉 '
            : '';

        return `<div>${mark}${v}</div>`;
      })
      .join('');
}

function showCurrent() {
  if (
    currentIndex >= 0 &&
    currentIndex < generatedPins.length
  ) {
    pinEl.innerText =
      generatedPins[currentIndex];
  }

  updateHistory();
  updateCount();
}

function generateNextPin() {
  const tested = getAllTestedSet();

  if (tested.size >= 10000) {
    pinEl.innerText = 'DONE';
    return;
  }

  let pin;

  do {
    pin = Math.floor(Math.random() * 10000)
      .toString()
      .padStart(4,...