Skip to content

Commit

Permalink
Resiliency Bugfixes (#15)
Browse files Browse the repository at this point in the history
~ Fixed crash + improve handling of when unrecognized keyboards are connected
~ Fixed startup crash on Windows 11 by updating `cmake-js`: See cmake-js/cmake-js#289
~ Bump `minimist` to resolve security issue
  • Loading branch information
donn committed Dec 31, 2022
1 parent 99c3872 commit 628e192
Show file tree
Hide file tree
Showing 11 changed files with 6,762 additions and 6,383 deletions.
12,835 changes: 6,598 additions & 6,237 deletions OSAcknowledgements.txt

Large diffs are not rendered by default.

29 changes: 12 additions & 17 deletions include/nuphy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,9 @@ class NuPhy { // Abstract
std::string requestPath;
uint16_t firmware;

NuPhy(
std::string dataPath,
std::string requestPath,
uint16_t firmware
)
: dataPath(dataPath), requestPath(requestPath), firmware(firmware) {}
NuPhy(std::string dataPath, std::string requestPath, uint16_t firmware)
: dataPath(dataPath), requestPath(requestPath), firmware(firmware) {
}

std::vector< uint32_t > getKeymap(bool mac = false);
void setKeymap(const std::vector< uint32_t > &keymap, bool mac = false);
Expand Down Expand Up @@ -89,11 +86,7 @@ class NuPhy { // Abstract

class Air75 : public NuPhy {
public:
Air75(
std::string dataPath,
std::string requestPath,
uint16_t firmware
)
Air75(std::string dataPath, std::string requestPath, uint16_t firmware)
: NuPhy(dataPath, requestPath, firmware) {}

virtual std::string getName() { return "Air75"; }
Expand Down Expand Up @@ -133,11 +126,7 @@ class Air75 : public NuPhy {

class Halo75 : public NuPhy {
public:
Halo75(
std::string dataPath,
std::string requestPath,
uint16_t firmware
)
Halo75(std::string dataPath, std::string requestPath, uint16_t firmware)
: NuPhy(dataPath, requestPath, firmware) {}

virtual std::string getName() { return "Halo75"; }
Expand All @@ -149,7 +138,7 @@ class Halo75 : public NuPhy {
return mac ? Halo75::indicesByKeyNameMac :
Halo75::indicesByKeyNameWin;
}

virtual std::vector< uint8_t > getKeymapReportHeader(bool mac = false) {
return mac ? std::vector< uint8_t >(
{0x05, 0x84, 0xd8, 0x00, 0x00, 0x00}
Expand All @@ -176,4 +165,10 @@ class Halo75 : public NuPhy {
indicesByKeyNameMac;
};

class unsupported_keyboard : public std::runtime_error {
public:
unsupported_keyboard(const std::string &what = "")
: std::runtime_error(what) {}
};

#endif
24 changes: 17 additions & 7 deletions index.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,15 @@ function createWindow() {
role: "help",
submenu: [
{
label: "Repo",
label: "Report A Bug",
click: async () => {
await shell.openExternal(
"https://github.com/donn/nudelta/issues"
);
},
},
{
label: "Code Repository",
click: async () => {
await shell.openExternal(
"https://github.com/donn/nudelta"
Expand Down Expand Up @@ -182,13 +190,15 @@ async function sendKeyboardInfo(sender) {
sender.send("get-keyboard-info-reply", { info });
} catch (err) {
let message = err.message;
let commands = message.split("\n\n")[1];
if (commands ?? false) {
clipboard.writeText(commands);
message =
"Unable to read HID devices. Please run the commands copied to your clipboard in a terminal window then restart Nudelta.";
if (err.kind === "Permissions Error") {
let commands = message.split("\n\n")[1];
if (commands ?? false) {
clipboard.writeText(commands);
message =
"Unable to read HID devices. Please run the commands copied to your clipboard in a terminal window then restart Nudelta.";
}
}
dialog.showErrorBox("Permissions Error", message);
dialog.showErrorBox(err.kind, message);
}
}

Expand Down
42 changes: 34 additions & 8 deletions lib/nuphy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ NuPhy::Handles NuPhy::getHandles() {
}

if (dataHandle == nullptr || requestHandle == nullptr) {
throw std::runtime_error("Failed to open device. Ensure your permissions are properly set up.");
throw std::runtime_error(
"Failed to open device. Ensure your permissions are properly set up."
);
}

auto cleanup = [](NuPhy::Handles &handles) {
Expand Down Expand Up @@ -159,6 +161,7 @@ std::shared_ptr< NuPhy > NuPhy::find() {
};

uint16_t firmware = 0x0;
std::string manufacturerString = "";
std::optional< std::string > productName;
std::optional< std::string > dataPath;
std::optional< std::string > requestPath;
Expand All @@ -176,16 +179,17 @@ std::shared_ptr< NuPhy > NuPhy::find() {
if (path.find(writeCol) != -1) {
if (requestPath.has_value()) {
throw std::runtime_error(
"Multiple NuPhy Air75 keyboards found! Please keep only one plugged in.\n"
"Multiple keyboards with the same product ID found! Please ensure only one keyboard is plugged in.\n"
);
}
productName = to_utf8(seeker->product_string);
requestPath = seeker->path;
firmware = seeker->release_number;
manufacturerString = to_utf8(seeker->manufacturer_string);
} else if (path.find(dataCol) != -1) {
if (dataPath.has_value()) {
throw std::runtime_error(
"Multiple NuPhy Air75 keyboards found! Please keep only one plugged in.\n"
"Multiple keyboards with the same product ID found! Please ensure only one keyboard is plugged in.\n"
);
}
productName = to_utf8(seeker->product_string);
Expand All @@ -196,12 +200,20 @@ std::shared_ptr< NuPhy > NuPhy::find() {
}

if (dataPath.has_value() && requestPath.has_value()) {
return createKeyboard(
auto keyboard = createKeyboard(
productName.value(),
dataPath.value(),
requestPath.value(),
firmware
);
if (keyboard == nullptr) {
throw unsupported_keyboard(fmt::format(
"No supported keyboards found, but a similar keyboard, '{} {}', has been found.\n\nIf you believe this keyboard not being supported is an error, please file a bug report.",
manufacturerString,
productName.value()
));
}
return keyboard;
}

return nullptr;
Expand All @@ -215,7 +227,9 @@ std::shared_ptr< NuPhy > NuPhy::find() {
hid_free_enumeration(seeker);
};

bool unsupportedDetected = false;
bool multipleWarned = false;
std::string productString = "";
while (seeker != nullptr) {
if (seeker->interface_number == 1) {
if (keyboard != nullptr) {
Expand All @@ -234,23 +248,35 @@ std::shared_ptr< NuPhy > NuPhy::find() {
throw permissions_error(hidAccessFailureMessage);
}
auto productName = to_utf8(seeker->product_string);
productString = productName;
if (auto manufacturerStringW = seeker->manufacturer_string) {
// There is no manufacturerString on the Linux/libusb
// implementation.
auto manufacturerName = to_utf8(manufacturerStringW);
productString =
fmt::format("{} {}", manufacturerName, productName);
}
keyboard = createKeyboard(
productName,
seeker->path,
seeker->path,
seeker->release_number
);
if (keyboard == nullptr) {
throw std::runtime_error(fmt::format(
"The NuPhy {} is currently unsupported.",
productName
));
unsupportedDetected = true;
}
}
}
seeker = seeker->next;
}

if (keyboard == nullptr && unsupportedDetected) {
throw unsupported_keyboard(fmt::format(
"No supported keyboards found, but a similar keyboard, '{}', has been found.\n\nIf you believe this keyboard not being supported is an error, please file a bug report.",
productString
));
}

return keyboard;
}
#endif
Expand Down
7 changes: 3 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
{
"name": "nudelta",
"author": "Mohamed Gaber <me@donn.website>",
"version": "0.6.0",
"version": "0.6.1",
"license": "GPL-3.0-or-later",
"homepage": "https://github.com/donn/nudelta#readme",
"description": "An open-source alternative to the NuPhy Console",
"dependencies": {
"@fontsource/nunito": "^4.5.11",
"axios": "^0.21.1",
"fs-extra": "^10.1.0",
"yaml": "^2.1.3"
},
Expand All @@ -24,7 +23,7 @@
"@rollup/plugin-node-resolve": "^9.0.0",
"@rollup/plugin-url": "^8.0.1",
"@rollup/plugin-yaml": "^4.0.1",
"cmake-js": "^7.0.0",
"cmake-js": "^7.1.1",
"electron": "^21.2.1",
"electron-builder": "^23.6.0",
"fast-glob": "^3.2.12",
Expand Down Expand Up @@ -77,4 +76,4 @@
"tabWidth": 4,
"quoteProps": "consistent"
}
}
}
16 changes: 8 additions & 8 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,15 @@ std::shared_ptr< NuPhy > getKeyboard() {

if (keyboard->dataPath == keyboard->requestPath) {
p("Found NuPhy {} at path {} (Firmware {:04x})\n",
keyboard->getName(),
keyboard->dataPath,
keyboard->firmware);
keyboard->getName(),
keyboard->dataPath,
keyboard->firmware);
} else {
p("Found NuPhy {} at paths ({}, {}) (Firmware {:04x})\n",
keyboard->getName(),
keyboard->dataPath,
keyboard->requestPath,
keyboard->firmware);
keyboard->getName(),
keyboard->dataPath,
keyboard->requestPath,
keyboard->firmware);
}

return keyboard;
Expand All @@ -66,7 +66,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
}

SSCO_Fn(printFirmware) {
auto air75 = getKeyboard();
auto keyboard = getKeyboard();
}

SSCO_Fn(resetKeymap) {
Expand Down
13 changes: 11 additions & 2 deletions src/node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ Napi::Value getKeyboardInfo(const Napi::CallbackInfo &info) {
keyboard->firmware
);

if (keyboard->dataPath == keyboard->requestPath && keyboard->dataPath.length() <= 20) {
if (keyboard->dataPath == keyboard->requestPath
&& keyboard->dataPath.length() <= 20) {
string = fmt::format("{} at {}", string, keyboard->dataPath);
}

Expand All @@ -46,7 +47,15 @@ Napi::Value getKeyboardInfo(const Napi::CallbackInfo &info) {

return object;
} catch (permissions_error &e) {
Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();
auto error = Napi::Error::New(env, e.what());
auto exception = error.Value();
exception["kind"] = "Permissions Error";
napi_throw(env, exception);
} catch (unsupported_keyboard &e) {
auto error = Napi::Error::New(env, e.what());
auto exception = error.Value();
exception["kind"] = "Unsupported Keyboard";
napi_throw(env, exception);
}
return env.Null();
}
Expand Down
2 changes: 1 addition & 1 deletion ui/src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ function redrawOptions() {
e.appendChild(
n("p", (e) => {
e.innerHTML =
"No keyboard found.<br />Make sure it's plugged in via USB, then File > Reload Keyboard to retry.";
"No supported keyboard found.<br />Make sure it's plugged in via USB, then File > Reload Keyboard to retry.";
})
);
})
Expand Down
Loading

0 comments on commit 628e192

Please sign in to comment.