Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use with Vite #92

Open
Techiton opened this issue Apr 7, 2023 · 2 comments
Open

Use with Vite #92

Techiton opened this issue Apr 7, 2023 · 2 comments

Comments

@Techiton
Copy link

Techiton commented Apr 7, 2023

How can i use this package with vite and astrojs, i was trying to implement this but i keep on getting this error

[0] 9:35:44 PM [vite] Internal server error: "ESM integration proposal for Wasm" is not supported currently. Use vite-plugin-wasm or other community plugins to handle this. Alternatively, you can use `.wasm?init` or `.wasm?url`. See https://vitejs.dev/guide/features.html#webassembly for more details.
[0]       at Context.load (file:///C:/Users/dynam/dosscord-astro/node_modules/.pnpm/[email protected]_@[email protected]/node_modules/vite/dist/node/chunks/dep-79892de8.js:41945:19)
[0]       at Object.load (file:///C:/Users/dynam/dosscord-astro/node_modules/.pnpm/[email protected]_@[email protected]/node_modules/vite/dist/node/chunks/dep-79892de8.js:43360:46)
[0]       at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
[0]       at async loadAndTransform (file:///C:/Users/dynam/dosscord-astro/node_modules/.pnpm/[email protected]_@[email protected]/node_modules/vite/dist/node/chunks/dep-79892de8.js:41038:24)

I tried installing the vite plugin and using .wasm?init or .wasm?url and it still returns that error

@stanleyyzhu
Copy link

I got the exactly same error but turned out that I can use the "argon2-bundled.min.js" instead

import argon2 from 'argon2-browser/dist/argon2-bundled.min.js';

@peterhirn
Copy link

peterhirn commented Jan 24, 2024

@Techiton Did you figure out a way to make this work?

Update

I was able to make it work with Astro/Vite based on https://github.com/antelle/argon2-browser/blob/master/docs/js/calc.js

import argon2Wasm from "argon2-browser/dist/argon2-simd.wasm?url";
import argon2Js from "argon2-browser/dist/argon2.js?url";

interface Module {
  ALLOC_NORMAL: number;
  wasmBinary: ArrayBuffer;
  wasmJSMethod: string;
  wasmMemory: WebAssembly.Memory;
  buffer: ArrayBuffer;
  TOTAL_MEMORY: number;
  postRun: () => void;
  allocate: (array: Uint8Array, type: string, allocator: number) => Uint8Array;
  _free: (array: Uint8Array) => void;
  _argon2_hash_ext: (
    timeCost: number,
    memoryCost: number,
    parallelism: number,
    pass: Uint8Array,
    passLenght: number,
    salt: Uint8Array,
    saltLength: number,
    hash: Uint8Array,
    hashLength: number,
    encoded: Uint8Array,
    encodedLength: number,
    type: number,
    secret: Uint8Array | number,
    secretLength: number,
    ad: Uint8Array | number,
    adLenght: number,
    version: number,
  ) => number;
  _argon2_encodedlen: (
    timeCost: number,
    memoryCost: number,
    parallelism: number,
    saltLength: number,
    hashLength: number,
    type: number,
  ) => number;
  _argon2_error_message: (res: number) => Uint8Array;
  UTF8ToString: (array: Uint8Array) => string;
}

declare global {
  // eslint-disable-next-line
  var Module: Module;
}

const loadScript = (src: string) =>
  new Promise((resolve, reject) => {
    const element = document.createElement("script");
    element.src = src;
    element.onload = resolve;
    element.onerror = reject;
    document.body.appendChild(element);
  });

const encodeUtf8 = (str: string) => new TextEncoder().encode(str);

const allocate = (array: Uint8Array) =>
  globalThis.Module.allocate(array, "i8", globalThis.Module.ALLOC_NORMAL);

const initialize = async (memoryCost: number) => {
  if (globalThis.Module?._argon2_hash_ext !== undefined) {
    return;
  }

  const KB = 1024 * 1024;
  const MB = 1024 * KB;
  const GB = 1024 * MB;
  const WASM_PAGE_SIZE = 64 * 1024;

  const totalMemory = (2 * GB - 64 * KB) / 1024 / WASM_PAGE_SIZE;
  const initialMemory = Math.min(
    Math.max(Math.ceil((memoryCost * 1024) / WASM_PAGE_SIZE), 256) + 256,
    totalMemory,
  );

  const wasmMemory = new WebAssembly.Memory({
    initial: initialMemory,
    maximum: totalMemory,
  });

  const wasm = await fetch(argon2Wasm);
  const wasmBinary = await wasm.arrayBuffer();

  const moduleLoaded = new Promise((resolve) => {
    globalThis.Module = {
      wasmBinary,
      wasmJSMethod: "native-wasm",
      wasmMemory: wasmMemory,
      buffer: wasmMemory.buffer,
      TOTAL_MEMORY: initialMemory * WASM_PAGE_SIZE,
      postRun: resolve,
    } as Module;
  });

  await loadScript(argon2Js);
  await moduleLoaded;
};

const generateSalt = (length: number) => {
  const array = new Uint8Array(length);
  self.crypto.getRandomValues(array);
  return array;
};

export const hash = async (password: string) => {
  // NOTE: Using dovecot defaults with increased parallelism
  const type = 2;
  const timeCost = 3;
  const memoryCost = 65536;
  const parallelism = 4;
  const hashLength = 32;
  const saltLength = 16;

  await initialize(memoryCost);

  const passEncoded = encodeUtf8(password);
  const pwd = allocate(passEncoded);
  const salt = allocate(generateSalt(saltLength));

  const encodedLength = globalThis.Module._argon2_encodedlen(
    timeCost,
    memoryCost,
    parallelism,
    saltLength,
    hashLength,
    type,
  );

  const hash = allocate(new Uint8Array(hashLength));
  const encoded = allocate(new Uint8Array(encodedLength + 1));

  const result = globalThis.Module._argon2_hash_ext(
    timeCost,
    memoryCost,
    parallelism,
    pwd,
    passEncoded.length,
    salt,
    saltLength,
    hash,
    hashLength,
    encoded,
    encodedLength,
    type,
    0,
    0,
    0,
    0,
    0x13,
  );

  if (result !== 0) {
    throw Error(
      globalThis.Module.UTF8ToString(
        globalThis.Module._argon2_error_message(result),
      ),
    );
  }

  const output = globalThis.Module.UTF8ToString(encoded);

  globalThis.Module._free(pwd);
  globalThis.Module._free(salt);
  globalThis.Module._free(hash);
  globalThis.Module._free(encoded);

  return output;
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants