Skip to content

Commit

Permalink
Init support to Async key gen
Browse files Browse the repository at this point in the history
  • Loading branch information
Sirherobrine23 committed Aug 22, 2023
1 parent 1719adf commit 0de2847
Show file tree
Hide file tree
Showing 6 changed files with 215 additions and 48 deletions.
119 changes: 119 additions & 0 deletions addons/genKey/key_gen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -306,15 +306,134 @@ namespace gereneate_Keys {
}
}

namespace asyncGenerateKeys {
class privateKeyWorker : public Napi::AsyncWorker {
private:
wg_key keyg;
wg_key_b64_string pskString;
public:
~privateKeyWorker() {}
privateKeyWorker(const Napi::Function& callback) : AsyncWorker(callback) {}
void Execute() override {
generatePrivate(keyg);
keyToBase64(pskString, keyg);
}
void OnOK() override {
Napi::HandleScope scope(Env());
Callback().Call({ Env().Null(), Napi::String::New(Env(), pskString) });
}
void OnError(const Napi::Error& e) override {
Napi::HandleScope scope(Env());
Callback().Call({ e.Value(), Env().Null() });
}
};

class publicKeyWorker : public Napi::AsyncWorker {
private:
std::string privKey;
wg_key interfacePrivateKey, interfacePublicKey;
wg_key_b64_string pubString;
public:
~publicKeyWorker() {}
publicKeyWorker(const Napi::Function& callback, std::string privateKey) : AsyncWorker(callback), privKey(privateKey) {}
void Execute() override {
keyFromBase64(interfacePrivateKey, privKey.c_str());
generatePublic(interfacePublicKey, interfacePrivateKey);
keyToBase64(pubString, interfacePublicKey);
}
void OnOK() override {
Napi::HandleScope scope(Env());
Callback().Call({ Env().Null(), Napi::String::New(Env(), pubString) });
}
void OnError(const Napi::Error& e) override {
Napi::HandleScope scope(Env());
Callback().Call({ e.Value(), Env().Null() });
}
};

class presharedKeyWorker : public Napi::AsyncWorker {
private:
wg_key keyg;
public:
~presharedKeyWorker() {}
presharedKeyWorker(const Napi::Function& callback) : AsyncWorker(callback) {}
void Execute() override {
generatePreshared(keyg);
}
void OnOK() override {
Napi::HandleScope scope(Env());
wg_key_b64_string pskString;
keyToBase64(pskString, keyg);
Callback().Call({ Env().Null(), Napi::String::New(Env(), pskString) });
}
void OnError(const Napi::Error& e) override {
Napi::HandleScope scope(Env());
Callback().Call({ e.Value(), Env().Null() });
}
};

Napi::Value genPresharedAsync(const Napi::CallbackInfo& info) {
const Napi::Env env = info.Env();
const Napi::Function callback = info[info.Length() - 1].As<Napi::Function>();
if (!(callback.IsFunction())) {
Napi::Error::New(env, "Require callback").ThrowAsJavaScriptException();
return env.Undefined();
}

// Callback function is latest argument
auto *Gen = new presharedKeyWorker(callback);
Gen->Queue();
return env.Undefined();
}

Napi::Value genPrivateAsync(const Napi::CallbackInfo& info) {
const Napi::Env env = info.Env();
const Napi::Function callback = info[info.Length() - 1].As<Napi::Function>();
if (!(callback.IsFunction())) {
Napi::Error::New(env, "Require callback").ThrowAsJavaScriptException();
return env.Undefined();
}

// Callback function is latest argument
auto *Gen = new privateKeyWorker(callback);
Gen->Queue();
return env.Undefined();
}

Napi::Value genPublicAsync(const Napi::CallbackInfo& info) {
const Napi::Env env = info.Env();
if (!(info[0].IsString())) {
Napi::Error::New(env, "Require private key").ThrowAsJavaScriptException();
return env.Undefined();
}
const Napi::Function callback = info[info.Length() - 1].As<Napi::Function>();
if (!(callback.IsFunction())) {
Napi::Error::New(env, "Require callback").ThrowAsJavaScriptException();
return env.Undefined();
}

// Callback function is latest argument
auto *Gen = new publicKeyWorker(callback, info[0].ToString().Utf8Value().c_str());
Gen->Queue();
return env.Undefined();
}
}

Napi::Object initKeyGen(Napi::Env env) {
const Napi::Object keyGen = Napi::Object::New(env);
return keyGen;
}

Napi::Object Init(Napi::Env env, Napi::Object exports) {
// Sync
exports.Set("presharedKey", Napi::Function::New(env, gereneate_Keys::presharedKey));
exports.Set("genPrivateKey", Napi::Function::New(env, gereneate_Keys::privateKey));
exports.Set("getPublicKey", Napi::Function::New(env, gereneate_Keys::publicKey));

// Async
exports.Set("presharedKeyAsync", Napi::Function::New(env, asyncGenerateKeys::genPresharedAsync));
exports.Set("genPrivateKeyAsync", Napi::Function::New(env, asyncGenerateKeys::genPrivateAsync));
exports.Set("getPublicKeyAsync", Napi::Function::New(env, asyncGenerateKeys::genPublicAsync));
return exports;
}
NODE_API_MODULE(addon, Init);
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "wireguard-tools.js",
"version": "1.7.1",
"version": "1.7.2",
"description": "Control your wireguard interface from node.js, not a wireguard-tools wrapper!",
"main": "src/index.js",
"types": "src/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion src/interfaces.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ if (process.platform !== "win32" && (userInfo()).uid === 0) {
const interfaceName = String(((process.env.WG_INETRFACE||"").length > 0) ? process.env.WG_INETRFACE : (process.platform === "darwin" ? "utun" : "shtest").concat(String(randomInt(20, 1023))));
const deviceConfig: Bridge.wireguardInterface = {
portListen: randomInt(1024, 65535),
privateKey: utils.genPrivateKey(),
privateKey: utils.genPrivate(),
replacePeers: true,
Address: [],
peers: {}
Expand Down
37 changes: 2 additions & 35 deletions src/utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,8 @@
const { format } = require("node:util");
const fs = require("node:fs");
const utils = require("../src/utils/index");
const { randomInt } = require("node:crypto");
const randomGen = randomInt(5000, 9999);
import fs from "node:fs";
import * as utils from "../src/utils/index";
const wg0 = fs.readFileSync(__dirname+"/../configsExamples/wg0.ini", "utf8"); // Server config
const wg1 = fs.readFileSync(__dirname+"/../configsExamples/wg1.ini", "utf8"); // Client config

// Key Generation
describe("Key Gen", () => {
it("Without Preshared key", () => {
const withOut = utils.keygen();
if (!withOut["preshared"]) return;
throw new Error("Keygen failed");
});
it("with Preshared key", () => {
const withPre = utils.keygen(true);
if (withPre["preshared"]) return;
throw new Error("Keygen failed");
});
it(format("Generate %f pre-shared keys", randomGen), () => {
const keyMap = new Set();
for (let i = 0; i < randomGen; i++) {
const key = utils.genPresharedKey();
if (keyMap.has(key)) throw new Error(format("Keygen failed, generate %f at time", keyMap.size));
keyMap.add(key);
}
});
it(format("Generate %f private keys", randomGen), () => {
const keyMap = new Set();
for (let i = 0; i < randomGen; i++) {
const key = utils.genPrivateKey();
if (keyMap.has(key)) throw new Error(format("Keygen failed, generate %f at time", keyMap.size));
keyMap.add(key);
}
});
});

describe("Parse and Create config", function() {
it("Parse server config", () => {
utils.config.parseConfig(wg0);
Expand Down
29 changes: 29 additions & 0 deletions src/utils/keygen.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {
genPreshared, genPresharedAsync,
genPrivate, genPrivateAsync,
genPublic, genPublicAsync,
keygen, keygenAsync
} from "./keygen";

const keysToGen = Array(8 ** 3).fill(null);

// Async
describe("Wireguard generate keys Async", function() {
it("Preshared", async () => genPresharedAsync());
it("Private", async () => genPrivateAsync());
it("Public", async () => genPublicAsync(await genPrivateAsync()));
it("Generate keys without preshared", async () => keygenAsync());
it("Generate keys with preshared", async () => keygenAsync(true));
it(`Random keys ${keysToGen.length} with preshared`, () => Promise.all(keysToGen.map(async () => keygenAsync(true))));
it(`Random keys ${keysToGen.length} without preshared`, () => Promise.all(keysToGen.map(async () => keygenAsync())));
});

describe("Wireguard generate keys Sync", function() {
it("Preshared", () => genPreshared());
it("Private", () => genPrivate());
it("Public", () => genPublic(genPrivate()));
it("Generate keys without preshared", () => keygen());
it("Generate keys with preshared", () => keygen(true));
it(`Random keys ${keysToGen.length} with preshared`, () => keysToGen.map(() => keygen(true)));
it(`Random keys ${keysToGen.length} without preshared`, () => keysToGen.map(() => keygen()));
});
74 changes: 63 additions & 11 deletions src/utils/keygen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,78 @@ export type keyObjectPreshered = keyObject & {preshared: string};
* Create a pre-shared key quickly by returning a string with the base64 of the key.
*
*/
export function genPresharedKey(): string {
export async function genPresharedAsync(): Promise<string> {
return new Promise((done, reject) => addonKeyGen["presharedKeyAsync"]((err, key) => err ? reject(err) : done(key)));
}

/**
* Create a Private key returning its base64.
*
*/
export async function genPrivateAsync(): Promise<string> {
return new Promise((done, reject) => addonKeyGen["genPrivateKeyAsync"]((err, key) => err ? reject(err) : done(key)));
}

/**
* Create your public key from a private key.
*
*/
export function genPublicAsync(privateKey: string): Promise<string> {
return new Promise((done, reject) => addonKeyGen["getPublicKeyAsync"](privateKey, (err, key) => err ? reject(err) : done(key)));
}


/**
* Generate Wireguard keys withou preshared key
*/
export async function keygenAsync(): Promise<keyObject>;

/**
* Generate Wireguard keys withou preshared key
*
* @param genPreshared - In object includes Preshared key, defaults is `false`
*/
export async function keygenAsync(genPreshared: false): Promise<keyObject>;

/**
* Generate Wireguard keys with pershared key.
*
* @param genPreshared - In object includes Preshared key, defaults is `false`
*/
export async function keygenAsync(genPreshared: true): Promise<keyObjectPreshered>;

/**
* Generate Wireguard keys without preshared key
*
* @param genPreshared - In object includes Preshared key, defaults is `false`
*/
export async function keygenAsync(genPresharedKey: boolean = false): Promise<keyObject|keyObjectPreshered> {
const keys = await genPrivateAsync().then(async privateKey => genPublicAsync(privateKey).then(pub => ({ private: privateKey, public: pub })));;
if (!genPresharedKey) return keys;
return genPresharedAsync().then(preshared => Object.assign(keys, {preshared}));
}

/**
* Create a pre-shared key quickly by returning a string with the base64 of the key.
*
*/
export function genPreshared(): string {
return addonKeyGen.presharedKey();
}

/**
* Create a Private key returning its base64.
*
*/
export function genPrivateKey(): string {
export function genPrivate(): string {
return addonKeyGen.genPrivateKey();
}

/**
* Create your public key from a private key.
*
*/
export function genPublicKey(privateKey: string): string {
export function genPublic(privateKey: string): string {
if (typeof privateKey !== "string") throw new Error("privateKey must be a string");
else if (privateKey.length > 44||44 > privateKey.length) throw new Error(`Invalid private key length (44), you length: (${privateKey.length})`);
return addonKeyGen.getPublicKey(privateKey);
Expand Down Expand Up @@ -53,16 +108,13 @@ export function keygen(genPreshared: true): keyObjectPreshered;
*
* @param genPreshared - In object includes Preshared key, defaults is `false`
*/
export function keygen(genPreshared: boolean = false): keyObject|keyObjectPreshered {
const privateKey = genPrivateKey();
const publicKey = genPublicKey(privateKey);
if (!genPreshared) return {
private: privateKey,
public: publicKey
};
export function keygen(genPresharedKey: boolean = false): keyObject|keyObjectPreshered {
const privateKey = genPrivate();
const publicKey = genPublic(privateKey);
if (!genPresharedKey) return { private: privateKey, public: publicKey };
return {
private: privateKey,
public: publicKey,
preshared: genPresharedKey()
preshared: genPreshared()
};
}

0 comments on commit 0de2847

Please sign in to comment.