Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions .github/scripts/build.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import util from 'node:util';
import process from 'node:process';
import fs from 'node:fs/promises';
import fs, { readFile } from 'node:fs/promises';
import child_process from 'node:child_process';
import events from 'node:events';
import path from 'node:path';
Expand Down Expand Up @@ -83,8 +83,16 @@ async function buildBindings(args, pkg) {

if (process.platform === 'darwin' && process.arch === 'arm64') {
// The "arm64" build is actually a universal binary
const armTar = `kerberos-v${pkg.version}-napi-v4-darwin-arm64.tar.gz`;
const x64Tar = `kerberos-v${pkg.version}-napi-v4-darwin-x64.tar.gz`;
// @ts-ignore
const {
binary: {
napi_versions: [
napiVersion
]
}
} = JSON.parse(await readFile(resolveRoot('package.json'), 'utf-8'));
const armTar = `kerberos-v${pkg.version}-napi-v${napiVersion}-darwin-arm64.tar.gz`;
const x64Tar = `kerberos-v${pkg.version}-napi-v${napiVersion}-darwin-x64.tar.gz`;
await fs.copyFile(resolveRoot('prebuilds', armTar), resolveRoot('prebuilds', x64Tar));
}

Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ jobs:
strategy:
matrix:
os: [macos-latest, windows-2022]
fail-fast: false
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
Expand All @@ -40,6 +41,7 @@ jobs:
strategy:
matrix:
linux_arch: [s390x, arm64, amd64]
fail-fast: false
steps:
- uses: actions/checkout@v4

Expand Down Expand Up @@ -69,6 +71,7 @@ jobs:
strategy:
matrix:
freebsd_arch: [aarch64, amd64]
fail-fast: false
steps:
- uses: actions/checkout@v4

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/webpack.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
- name: "Install dependencies"
shell: bash
run: |
npm install
npm install --ignore-scripts

- name: "Install dependencies in the Webpack bundle test package"
shell: bash
Expand Down
10 changes: 9 additions & 1 deletion lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,13 @@ async function initializeServer(service) {
return await promisifiedInitializeServer.call(this, service);
}

/**
* @private
*
* The NAPI version kerberos is configured to use, defined in kerberos.h.
*/
const definedNapiVersion = kerberos.definedNapiVersion;

module.exports = {
initializeClient,
initializeServer,
Expand All @@ -246,5 +253,6 @@ module.exports = {
GSS_MECH_OID_KRB5,
GSS_MECH_OID_SPNEGO,

version
version,
definedNapiVersion
};
12 changes: 8 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"url": "https://jira.mongodb.org/projects/NODE/issues/"
},
"dependencies": {
"node-addon-api": "^6.1.0",
"node-addon-api": "^8.5.0",
"prebuild-install": "^7.1.3"
},
"devDependencies": {
Expand Down Expand Up @@ -69,7 +69,7 @@
},
"binary": {
"napi_versions": [
4
9
]
},
"license": "Apache-2.0",
Expand Down
95 changes: 33 additions & 62 deletions src/kerberos.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "kerberos.h"

#include "kerberos_worker.h"

/// KerberosClient
Expand All @@ -13,22 +14,22 @@ struct InstanceData {
};

static constexpr napi_property_attributes writable_and_configurable =
static_cast<napi_property_attributes>(
static_cast<int>(napi_writable) | static_cast<int>(napi_configurable));
static_cast<napi_property_attributes>(static_cast<int>(napi_writable) |
static_cast<int>(napi_configurable));

inline String NewMaybeWideString(Env env, const char* str) {
return String::New(env, str);
}
#ifdef _WIN32
inline String NewMaybeWideString(Env env, const WCHAR* str) {
static_assert(sizeof(std::wstring::value_type) == sizeof(std::u16string::value_type),
"wstring and u16string have the same value type on Windows");
"wstring and u16string have the same value type on Windows");
std::wstring wstr(str);
std::u16string u16(wstr.begin(), wstr.end());
return String::New(env, u16);
}
#endif
}
} // namespace

std::string ToStringWithNonStringAsEmpty(Napi::Value value) {
if (!value.IsString()) {
Expand All @@ -38,7 +39,8 @@ std::string ToStringWithNonStringAsEmpty(Napi::Value value) {
}

int KerberosClient::ParseWrapOptionsProtect(const Napi::Object& options) {
if (!options.Has("protect")) return 0;
if (!options.Has("protect"))
return 0;

if (!options.Get("protect").IsBoolean()) {
throw TypeError::New(options.Env(), "options.protect must be a boolean.");
Expand All @@ -49,18 +51,16 @@ int KerberosClient::ParseWrapOptionsProtect(const Napi::Object& options) {
}

Function KerberosClient::Init(Napi::Env env) {
return
DefineClass(env,
"KerberosClient",
{
InstanceMethod("step", &KerberosClient::Step, writable_and_configurable),
InstanceMethod("wrap", &KerberosClient::WrapData, writable_and_configurable),
InstanceMethod("unwrap", &KerberosClient::UnwrapData, writable_and_configurable),
InstanceAccessor("username", &KerberosClient::UserNameGetter, nullptr),
InstanceAccessor("response", &KerberosClient::ResponseGetter, nullptr),
InstanceAccessor("responseConf", &KerberosClient::ResponseConfGetter, nullptr),
InstanceAccessor("contextComplete", &KerberosClient::ContextCompleteGetter, nullptr)
});
return DefineClass(
env,
"KerberosClient",
{InstanceMethod("step", &KerberosClient::Step, writable_and_configurable),
InstanceMethod("wrap", &KerberosClient::WrapData, writable_and_configurable),
InstanceMethod("unwrap", &KerberosClient::UnwrapData, writable_and_configurable),
InstanceAccessor("username", &KerberosClient::UserNameGetter, nullptr),
InstanceAccessor("response", &KerberosClient::ResponseGetter, nullptr),
InstanceAccessor("responseConf", &KerberosClient::ResponseConfGetter, nullptr),
InstanceAccessor("contextComplete", &KerberosClient::ContextCompleteGetter, nullptr)});
}

Object KerberosClient::NewInstance(Napi::Env env, std::shared_ptr<krb_client_state> state) {
Expand All @@ -71,8 +71,7 @@ Object KerberosClient::NewInstance(Napi::Env env, std::shared_ptr<krb_client_sta
return obj;
}

KerberosClient::KerberosClient(const CallbackInfo& info)
: ObjectWrap(info) {}
KerberosClient::KerberosClient(const CallbackInfo& info) : ObjectWrap(info) {}

std::shared_ptr<krb_client_state> KerberosClient::state() const {
return _state;
Expand Down Expand Up @@ -102,16 +101,14 @@ Value KerberosClient::ContextCompleteGetter(const CallbackInfo& info) {

/// KerberosServer
Function KerberosServer::Init(Napi::Env env) {
return
DefineClass(env,
"KerberosServer",
{
InstanceMethod("step", &KerberosServer::Step, writable_and_configurable),
InstanceAccessor("username", &KerberosServer::UserNameGetter, nullptr),
InstanceAccessor("response", &KerberosServer::ResponseGetter, nullptr),
InstanceAccessor("targetName", &KerberosServer::TargetNameGetter, nullptr),
InstanceAccessor("contextComplete", &KerberosServer::ContextCompleteGetter, nullptr)
});
return DefineClass(
env,
"KerberosServer",
{InstanceMethod("step", &KerberosServer::Step, writable_and_configurable),
InstanceAccessor("username", &KerberosServer::UserNameGetter, nullptr),
InstanceAccessor("response", &KerberosServer::ResponseGetter, nullptr),
InstanceAccessor("targetName", &KerberosServer::TargetNameGetter, nullptr),
InstanceAccessor("contextComplete", &KerberosServer::ContextCompleteGetter, nullptr)});
}

Object KerberosServer::NewInstance(Napi::Env env, std::shared_ptr<krb_server_state> state) {
Expand All @@ -122,8 +119,7 @@ Object KerberosServer::NewInstance(Napi::Env env, std::shared_ptr<krb_server_sta
return obj;
}

KerberosServer::KerberosServer(const CallbackInfo& info)
: ObjectWrap(info) {}
KerberosServer::KerberosServer(const CallbackInfo& info) : ObjectWrap(info) {}

std::shared_ptr<krb_server_state> KerberosServer::state() const {
return _state;
Expand Down Expand Up @@ -154,31 +150,8 @@ Value KerberosServer::ContextCompleteGetter(const CallbackInfo& info) {
return Boolean::New(Env(), state()->context_complete);
}

void TestMethod(const CallbackInfo& info) {
std::string string = info[0].ToString();
bool shouldError = info[1].ToBoolean();

std::string optionalString;
Function callback;
if (info[2].IsFunction()) {
callback = info[2].As<Function>();
} else {
optionalString = info[2].ToString();
callback = info[3].As<Function>();
}

KerberosWorker::Run(callback, "kerberos:TestMethod", [=](KerberosWorker::SetOnFinishedHandler onFinished) {
return onFinished([=](KerberosWorker* worker) {
Napi::Env env = worker->Env();
if (shouldError) {
worker->Call(std::initializer_list<napi_value>
{ Error::New(env).Value(), env.Null() });
} else {
worker->Call(std::initializer_list<napi_value>
{ env.Null(), String::New(env, optionalString) });
}
});
});
Value GetDefinedNapiVersion(const CallbackInfo& info) {
return String::New(info.Env(), std::to_string(NAPI_VERSION));
}

static Object Init(Env env, Object exports) {
Expand All @@ -190,18 +163,16 @@ static Object Init(Env env, Object exports) {
Function KerberosServerCtor = KerberosServer::Init(env);
exports["KerberosClient"] = KerberosClientCtor;
exports["KerberosServer"] = KerberosServerCtor;
env.SetInstanceData(new InstanceData {
Reference<Function>::New(KerberosClientCtor, 1),
Reference<Function>::New(KerberosServerCtor, 1)
});
env.SetInstanceData(new InstanceData{Reference<Function>::New(KerberosClientCtor, 1),
Reference<Function>::New(KerberosServerCtor, 1)});
exports["initializeClient"] = Function::New(env, InitializeClient);
exports["initializeServer"] = Function::New(env, InitializeServer);
exports["principalDetails"] = Function::New(env, PrincipalDetails);
exports["checkPassword"] = Function::New(env, CheckPassword);
exports["_testMethod"] = Function::New(env, TestMethod);
exports["definedNapiVersion"] = Function::New(env, GetDefinedNapiVersion);
return exports;
}

NODE_API_MODULE(kerberos, Init)

}
} // namespace node_kerberos
16 changes: 5 additions & 11 deletions src/kerberos.h
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
#ifndef KERBEROS_NATIVE_EXTENSION_H
#define KERBEROS_NATIVE_EXTENSION_H

// We generally only target N-API version 4, but the instance data
// feature is only available in N-API version 6. However, it is
// available in all Node.js versions that have N-API version 4
#define NAPI_VERSION 6
// as an experimental feature (that has not been changed since then).
#define NAPI_EXPERIMENTAL
#define NODE_API_EXPERIMENTAL_NOGC_ENV_OPT_OUT
#define NAPI_VERSION 9

#include <napi.h>

#include "kerberos_common.h"

namespace node_kerberos {
Expand Down Expand Up @@ -69,11 +64,10 @@ void InitializeClient(const Napi::CallbackInfo& info);
void InitializeServer(const Napi::CallbackInfo& info);
void CheckPassword(const Napi::CallbackInfo& info);

// NOTE: explicitly used for unit testing `defineOperation`, not meant to be exported
void TestMethod(const Napi::CallbackInfo& info);

std::string ToStringWithNonStringAsEmpty(Napi::Value value);

}
Napi::Value GetDefinedNapiVersion(const Napi::CallbackInfo& info);

} // namespace node_kerberos

#endif // KERBEROS_NATIVE_EXTENSION_H
4 changes: 3 additions & 1 deletion test/bundling/webpack/install_kerberos.cjs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable no-console */
'use strict';

const { execSync } = require('node:child_process');
Expand All @@ -19,6 +20,7 @@ console.log(`kerberos Version: ${kerberosVersion}`);

xtrace('npm pack --pack-destination test/bundling/webpack', { cwd: kerberosRoot });

xtrace(`npm install --no-save kerberos-${kerberosVersion}.tgz`);
// --ignore-scripts: don't worry about downloading prebuilt binaries, we're only bundling
xtrace(`npm install --ignore-scripts --no-save kerberos-${kerberosVersion}.tgz`);

console.log('kerberos installed!');
4 changes: 4 additions & 0 deletions test/kerberos_tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -221,4 +221,8 @@ describe('Kerberos', function () {
});
});
});

it('definedNapiVersion() returns 9', function () {
expect(kerberos.definedNapiVersion()).to.equal('9');
});
});