2024年4月

canvas指纹生成


<script>
  const getDeviceInformation = () => {
    return {
      userAgent: navigator.userAgent,
      platform: navigator.platform,
      screenWidth: window.screen.width,
      screenHeight: window.screen.height,
    };
  };

  function sha256(hex) {
    return crypto.subtle
      .digest("SHA-256", new TextEncoder().encode(hex))
      .then((buffer) => {
        return Array.prototype.map
          .call(new Uint8Array(buffer), (x) =>
            ("00" + x.toString(16)).slice(-2)
          )
          .join("");
      });
  }

  const bin2hex = (base64) => {
    var raw = base64;
    console.log(raw);
    var hex = "";
    for (var i = 0; i < raw.length; i++) {
      var charCode = raw.charCodeAt(i).toString(16);
      hex += charCode.length === 1 ? "0" + charCode : charCode;
    }

    return hex;
  };
  const getFingerprintId = async (content, options = {}) => {
    if (!content) {
      console.error("content is empty");
      return null;
    }
    const canvas = document.createElement("canvas");
    const ctx = canvas.getContext("2d");
    // 如果不存在,则返回空值,说明不支持Canvas指纹
    if (!ctx) return null;

    const txt = content || "geekbang";
    ctx.textBaseline =
      options && options.textBaseline ? options.textBaseline : "top";
    ctx.font = options && options.font ? options.font : "14px 'Arial'";

    ctx.fillStyle =
      options && options.reactStyle ? options.reactStyle : "#f60";
    // 先画一个60x20矩形内容
    ctx.fillRect(125, 1, 60, 20);

    ctx.fillStyle =
      options && options.contentStyle ? options.contentStyle : "#069";
    // 把字填充到矩形内
    ctx.fillText(txt, 2, 15);

    const b64 = canvas.toDataURL().replace("data:image/png;base64,", "");
    const bin = atob(b64);
    const crc = bin2hex(bin.slice(-16, -12));

    const hash = await sha256(crc + JSON.stringify(getDeviceInformation()));

    document.write("<p>SHA-256 哈希值为: " + hash + "</p>");

    return hash;
  };

  window.onload = () => getFingerprintId("abc");
</script>