Skip to content

v1: replace native addon with Node.js crypto - #540

Open
ranisalt wants to merge 1 commit into
masterfrom
next
Open

ranisalt wants to merge 1 commit into
masterfrom
next

Conversation

@ranisalt

Copy link
Copy Markdown
Owner

Removes all native bindings and prebuilt binary infrastructure, transitioning the package to use the native Argon2 implementation now available in node:crypto starting with Node.js 24.7.0. This simplifies the codebase and CI/CD workflows.

  • BREAKING: Core implementation now delegates to node:crypto's Argon2, removing native bindings and related dependencies (bindings.gyp, .gitmodules + argon2 submodule, .clang-format, etc)
  • Remove all jobs related to building and testing native binaries

The package is now a thin wrapper around Node.js native Argon2 implementation, requiring Node.js 24.7.0 or newer. All legacy native code, build scripts, and related CI/CD complexity have been removed. It will continue working with prebuilt binaries in v0 at least until Node 22 is EOL, as explained in #469

@ranisalt ranisalt linked an issue Jul 17, 2026 that may be closed by this pull request
@sonarqubecloud

This comment was marked as low quality.

@ranisalt

Copy link
Copy Markdown
Owner Author

v1.0.0-alpha.1 has been released in NPM with the code from this branch

@ranisalt

Copy link
Copy Markdown
Owner Author

I consider relicensing to CC0 with this release. Argon2 is frozen, Node interface is unlikely to change significantly, and the library is thin enough that I don't expect big changes other than bumping dependencies, so it would benefit from a public domain license.

- Bump package version from 0.45.0 to 1.0.0 in package.json
- Rewrite the main module in ESM
- Remove unnecessary binary and files entries in package.json
@ashleigh-yeoman

ashleigh-yeoman commented Oct 20, 2026 •

Copy link
Copy Markdown

Since node 22 is still in maintenance LTS, is there some way of supporting both native node and prebuilt binaries?

Maybe a class for each argon2 approach that abstracts away the function? Something like this maybe? The argon2.js section probably won't work quite like that, but the idea is there of having a global that can be assigned for module-scope dependency injection

// native.mjs
import { argon2 } from "node:crypto";
import { promisify } from "node:util";
const fn = promisify(argon2);

export class NativeArgon2 {
  static hash(type, opts) {
    return fn(type, opts);
  }
}

// prebuilt.cjs
const gypBuild = require("node-gyp-build");
const { hash: bindingsHash } = gypBuild(__dirname);

class PrebuiltArgon2 {
  static hash(type, opts) {
    return bindingsHash(
      data: opts.associatedData,
      hashLength: opts.tagLength,
      m: opts.memory,
      p: opts.parallelism,
      password: Buffer.from(opts.message),
      salt: opts.nonce,
      secret: opts.secret,
      t: opts.passes,
      type,
      version: opts.version,
    );
  }
}

module.exports.PrebuiltArgon2 = PrebuiltArgon2;

// argon2.js
// ...

class StubArgon2 {
  static hash(type, opts) {
    throw new Error("Argon2Provider is not initialised");
  }
}

// Consumers of this package should do something similar to 
// https://github.com/wojtekmaj/react-pdf#import-worker-recommended
// and import the specific argon2 provider they want to use
export let Argon2Provider = StubArgon2;

// ...

export async function hash(password, options) {
  // ...
  const derivedKey = await Argon2Provider.hash(type, {
    // ...
  });
  // ...
}

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

Successfully merging this pull request may close these issues.

Offer a minimal wrapper option (no native libraries) now?

2 participants