Skip to content

Commit

Permalink
Merge pull request #2 from gerhardberger/master
Browse files Browse the repository at this point in the history
Fix crash on newer Node.js versions and extend API
  • Loading branch information
jpalumickas committed Jun 9, 2021
2 parents db967e7 + fbd24fd commit ec6154a
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 33 deletions.
3 changes: 3 additions & 0 deletions AppleLogin.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#import "AppleLogin.h"

@interface AppleLogin ()

@property (nonatomic, strong) NSWindow *window;
Expand Down Expand Up @@ -32,6 +33,7 @@ - (void)authorizationController:(ASAuthorizationController *)controller didCompl

if(appleIDCredential) {
NSString *idToken = [[NSString alloc] initWithData:appleIDCredential.identityToken encoding:NSUTF8StringEncoding];
NSString *code = [[NSString alloc] initWithData:appleIDCredential.authorizationCode encoding:NSUTF8StringEncoding];

NSPersonNameComponents *fullName = appleIDCredential.fullName;
NSDictionary *userDetails = @{
Expand All @@ -40,6 +42,7 @@ - (void)authorizationController:(ASAuthorizationController *)controller didCompl
@"lastName": fullName.familyName ?: @"",
@"email" : appleIDCredential.email ?: @"",
@"idToken" : idToken,
@"code" : code,
};

self.successBlock(userDetails);
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ ipcMain.on('sign-in-with-apple', async () => {
const data = await signInWithApple(nativeWindow);
// {
// idToken: 'TOKEN',
// code: 'CODE',
// firstName: 'John',
// middleName: 'Chris',
// lastName: 'Doe',
Expand Down
13 changes: 12 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,18 @@ const signInWithApple = async (mainWindow) => {
throw new Error('node-mac-sign-in-with-apple only works on macOS')
}

return await appleLogin.signInWithApple(mainWindow);
return new Promise((resolve, reject) => {
appleLogin.signInWithApple((result) => {
if (result.is_error === 'true') {
delete result.is_error;
reject(result);
return;
}

delete result.is_error;
resolve(result);
}, mainWindow);
})
};

module.exports = {
Expand Down
81 changes: 49 additions & 32 deletions main.mm
Original file line number Diff line number Diff line change
@@ -1,70 +1,87 @@
#import <AuthenticationServices/AuthenticationServices.h>
#import "./AppleLogin.h"

#include <map>
#include <napi.h>

Napi::ThreadSafeFunction ts_fn;
using namespace Napi;

ThreadSafeFunction tsfn;

static NSWindow *windowFromBuffer(const Napi::Buffer<uint8_t> &buffer) {
auto data = (NSView **)buffer.Data();
auto view = data[0];
return view.window;
}

Napi::Promise SignInWithApple(const Napi::CallbackInfo &info) {
Value SignInWithApple( const CallbackInfo& info )
{
Napi::Env env = info.Env();
Napi::Promise::Deferred deferred = Napi::Promise::Deferred::New(env);

if (info.Length() < 1) {
Napi::Error::New(info.Env(), "Wrong number of arguments")
if (info.Length() != 2) {
Error::New(info.Env(), "Wrong number of arguments")
.ThrowAsJavaScriptException();
}

Napi::Buffer<uint8_t> buffer = info[0].As<Napi::Buffer<uint8_t>>();
if (buffer.Length() != 8) {
Napi::Error::New(info.Env(), "Pointer buffer is invalid")
.ThrowAsJavaScriptException();
}
tsfn = ThreadSafeFunction::New(env, info[0].As<Function>(),
"Thread Safe Function", 0, 1, [](Napi::Env) {});

Napi::Buffer<uint8_t> buffer = info[1].As<Napi::Buffer<uint8_t>>();
NSWindow *win = windowFromBuffer(buffer);

AppleLogin *appleLogin = [[AppleLogin alloc] initWithWindow:win];

NSDictionary *result = [appleLogin initiateLoginProcess:^(NSDictionary * _Nonnull result) {
auto callback = [](Napi::Env env, Function jsCallback, std::map<std::string, std::string> *values) {
Napi::Object obj = Napi::Object::New(env);

for (auto const& v : (*values)) {
obj.Set(v.first, Napi::Value::From(env, v.second));
}

jsCallback.Call({Value::From(env, obj)});

delete values;
};

[appleLogin initiateLoginProcess:^(NSDictionary * _Nonnull result) {
std::map<std::string, std::string> *values = new std::map<std::string, std::string>();
(*values)["is_error"] = "false";

for (NSString* key in result) {
NSString *value = result[key];

if(value != nil && [value length] > 0) {
std::string napiKey = std::string([key UTF8String]);
Napi::Value napiValue = Napi::Value::From(env, [[NSString stringWithFormat:@"%@", value] UTF8String]);
obj.Set(napiKey, napiValue);
if (value != nil && [value length] > 0) {
std::string stringKey = std::string([key UTF8String]);
std::string stringValue = std::string([[NSString stringWithFormat:@"%@", value] UTF8String]);
(*values)[stringKey] = stringValue;
}
}

deferred.Resolve(obj);
napi_status status = tsfn.BlockingCall(values, callback);
if (status != napi_ok) {
NSLog(@"Error occured when running callback on the event loop.\n");
}

tsfn.Release();
} errorHandler:^(NSError * _Nonnull error) {
Napi::Object errorObj = Napi::Object::New(env);

errorObj.Set("code", Napi::Value::From(env, error.code));
errorObj.Set("message", Napi::Value::From(env, [error.description UTF8String]));
for (NSString* key in error.userInfo) {
NSString *value = error.userInfo[key];
std::string napiKey = std::string([key UTF8String]);
Napi::Value napiValue = Napi::Value::From(env, [[NSString stringWithFormat:@"%@", value] UTF8String]);
errorObj.Set(napiKey, napiValue);
std::map<std::string, std::string> *values = new std::map<std::string, std::string>();
(*values)["is_error"] = "true";
(*values)["code"] = std::string([[@(error.code) stringValue] UTF8String]);
(*values)["message"] = std::string([error.description UTF8String]);

napi_status status = tsfn.BlockingCall(values, callback);
if (status != napi_ok) {
NSLog(@"Error occured when running callback on the event loop.\n");
}

deferred.Reject(errorObj);
tsfn.Release();
}];

return deferred.Promise();
return Napi::Boolean::New(env, true);
}

// Initializes all functions exposed to JS.
Napi::Object Init(Napi::Env env, Napi::Object exports) {
exports.Set(Napi::String::New(env, "signInWithApple"),
Napi::Function::New(env, SignInWithApple));
Object Init(Env env, Object exports) {
exports.Set(String::New(env, "signInWithApple"),
Function::New(env, SignInWithApple));

return exports;
}
Expand Down

0 comments on commit ec6154a

Please sign in to comment.