node-windows-ucv/addon.cpp
Fedor Indutny dd9dd40da5 v1.0.0
2025-06-05 11:17:30 -07:00

132 lines
4.1 KiB
C++

#include <assert.h>
#include <windows.h>
#include <winrt/windows.foundation.metadata.h>
#include <winrt/windows.security.credentials.ui.h>
#include "napi.h"
using namespace winrt;
using namespace Windows::Security::Credentials::UI;
using namespace Windows::Foundation;
static inline std::string ConvertAvailability(
UserConsentVerifierAvailability availability) {
switch (availability) {
case UserConsentVerifierAvailability::Available:
return "available";
case UserConsentVerifierAvailability::DeviceBusy:
return "deviceBusy";
case UserConsentVerifierAvailability::DeviceNotPresent:
return "deviceNotPresent";
case UserConsentVerifierAvailability::DisabledByPolicy:
return "disabledByPolicy";
case UserConsentVerifierAvailability::NotConfiguredForUser:
return "notConfiguredForUser";
default:
return "unknown";
}
}
static inline std::string ConvertVerificationResult(
UserConsentVerificationResult result) {
switch (result) {
case UserConsentVerificationResult::Verified:
return "verified";
case UserConsentVerificationResult::DeviceBusy:
return "deviceBusy";
case UserConsentVerificationResult::DeviceNotPresent:
return "deviceNotPresent";
case UserConsentVerificationResult::DisabledByPolicy:
return "disabledByPolicy";
case UserConsentVerificationResult::NotConfiguredForUser:
return "notConfiguredForUser";
case UserConsentVerificationResult::RetriesExhausted:
return "retriesExhausted";
case UserConsentVerificationResult::Canceled:
return "canceled";
default:
return "unknown";
}
}
void CheckAvailability(const Napi::CallbackInfo& info) {
auto env = info.Env();
auto callback = info[0].As<Napi::Function>();
if (!callback.IsFunction()) {
NAPI_THROW(Napi::Error::New(env, "First argument must be a function"),
Napi::Value());
}
auto tsfn = Napi::ThreadSafeFunction::New(
env, callback, "windows-ucv.checkAvailability", 0, 1);
auto op = UserConsentVerifier::CheckAvailabilityAsync();
op.Completed([tsfn](IAsyncOperation<UserConsentVerifierAvailability> info,
AsyncStatus status) {
auto res = tsfn.BlockingCall([info, status](auto env, auto jsCallback) {
std::string result;
if (status == AsyncStatus::Completed) {
result = ConvertAvailability(info.GetResults());
} else {
result = "error";
}
jsCallback.Call({Napi::String::New(env, result)});
});
assert(res == napi_ok);
tsfn.Release();
});
}
void RequestVerification(const Napi::CallbackInfo& info) {
auto env = info.Env();
auto msg = info[0].As<Napi::String>();
if (!msg.IsString()) {
NAPI_THROW(Napi::Error::New(env, "First argument must be a string"),
Napi::Value());
}
auto callback = info[1].As<Napi::Function>();
if (!callback.IsFunction()) {
NAPI_THROW(Napi::Error::New(env, "Second argument must be a function"),
Napi::Value());
}
auto utf8 = msg.Utf8Value();
auto hstring = winrt::to_hstring(utf8);
auto tsfn = Napi::ThreadSafeFunction::New(
env, callback, "windows-ucv.requestVerification", 0, 1);
auto op = UserConsentVerifier::RequestVerificationAsync(hstring);
op.Completed([tsfn](IAsyncOperation<UserConsentVerificationResult> info,
AsyncStatus status) {
auto res = tsfn.BlockingCall([info, status](auto env, auto jsCallback) {
std::string result;
if (status == AsyncStatus::Completed) {
result = ConvertVerificationResult(info.GetResults());
} else {
result = "error";
}
jsCallback.Call({Napi::String::New(env, result)});
});
assert(res == napi_ok);
tsfn.Release();
});
}
Napi::Object Init(Napi::Env env, Napi::Object exports) {
exports.Set(Napi::String::New(env, "checkAvailability"),
Napi::Function::New(env, CheckAvailability));
exports.Set(Napi::String::New(env, "requestVerification"),
Napi::Function::New(env, RequestVerification));
return exports;
}
NODE_API_MODULE(windows - ucv, Init)