e.stopPropagation()}
+ onKeyUp={e => e.stopPropagation()}
>
-
-
-
- App: {currentVersions.appVersion}
-
- System: {currentVersions.systemVersion}
- >
- ) : (
- "Loading current versions..."
- )
- }
- />
-
-
+
+
+
+
+ App: {currentVersions.appVersion}
+
+ System: {currentVersions.systemVersion}
+ >
+ ) : (
+ "Loading current versions..."
+ )
+ }
/>
+
+
+
+
+
+
+
+
+
+ {
+ setHideCursor(e.target.checked);
+ }}
+ />
+
+
+ {
+ handleJigglerChange(e.target.checked);
+ }}
+ />
+
+
+
+
+
console.log("Absolute mouse mode clicked")}
+ >
+
+
+
+
+
+
+ Absolute
+
+
+ Most convenient
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Relative
+
+
+ Coming soon
+
+
+
+
+
+
+
+
-
-
-
-
- {
- setHideCursor(e.target.checked);
- }}
- />
-
-
- {
- handleJigglerChange(e.target.checked);
- }}
- />
-
+
+
-
-
-
console.log("Absolute mouse mode clicked")}
- >
-
-
-
-
-
-
- Absolute
-
-
- Most convenient
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Relative
-
-
- Coming soon
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- handleStreamQualityChange(e.target.value)}
- />
-
-
- {
- if (e.target.value === "custom") {
- setEdid("custom");
- setCustomEdidValue("");
- } else {
- handleEDIDChange(e.target.value as string);
- }
- }}
- options={[...edids, { value: "custom", label: "Custom" }]}
- />
-
- {customEdidValue !== null && (
- <>
-
-
setCustomEdidValue(e.target.value)}
- />
-
- handleEDIDChange(customEdidValue)}
- />
- {
- setCustomEdidValue(null);
- handleEDIDChange(defaultEdid);
- }}
- />
-
- >
- )}
-
-
- {isOnDevice && (
- <>
-
-
-
-
-
-
-
-
-
-
- Cloud Security
-
-
-
- • End-to-end encryption using WebRTC (DTLS and SRTP)
- • Zero Trust security model
- • OIDC (OpenID Connect) authentication
- • All streams encrypted in transit
-
-
-
-
- All cloud components are open-source and available on{" "}
-
- GitHub
-
- .
-
-
-
-
-
-
-
-
-
-
-
- {!isAdopted ? (
-
-
-
- ) : (
-
-
-
- Your device is adopted to JetKVM Cloud
-
-
- {
- if (deviceId) {
- if (
- window.confirm(
- "Are you sure you want to de-register this device?",
- )
- ) {
- deregisterDevice();
- }
- } else {
- notifications.error("No device ID available");
- }
- }}
- />
-
-
-
- )}
-
- >
- )}
-
- {isOnDevice ? (
- <>
-
-
-
-
-
- {localDevice?.authMode === "password" ? (
- {
- setLocalAuthModalView("deletePassword");
- setIsLocalAuthDialogOpen(true);
- }}
- />
- ) : (
- {
- setLocalAuthModalView("createPassword");
- setIsLocalAuthDialogOpen(true);
- }}
- />
- )}
-
-
- {localDevice?.authMode === "password" && (
-
- {
- setLocalAuthModalView("updatePassword");
- setIsLocalAuthDialogOpen(true);
- }}
- />
-
- )}
-
-
-
- >
- ) : null}
-
-
-
-
-
- {
- handleAutoUpdateChange(e.target.checked);
- }}
- />
-
-
- {
- handleDevChannelChange(e.target.checked);
- }}
- />
-
-
-
-
-
-
-
- {
- setCurrentTheme(e.target.value);
- handleThemeChange(e.target.value);
- }}
- />
-
-
-
-
-
-
-
- handleDevModeChange(e.target.checked)}
- />
-
-
- {settings.developerMode && (
-
-
handleSSHKeyChange(e.target.value)}
- placeholder="Enter your SSH public key"
- />
-
- The default SSH user is root .
-
-
-
-
-
- )}
-
- {
- settings.setDebugMode(e.target.checked);
- }}
- />
-
-
- {settings.debugMode && (
- <>
-
- handleUsbEmulationToggle(!usbEmulationEnabled)}
- />
-
- >
- )}
- {settings.debugMode && (
- {
- handleResetConfig();
- window.location.reload();
- }}
+ handleStreamQualityChange(e.target.value)}
/>
- )}
+
+ {
+ if (e.target.value === "custom") {
+ setEdid("custom");
+ setCustomEdidValue("");
+ } else {
+ handleEDIDChange(e.target.value as string);
+ }
+ }}
+ options={[...edids, { value: "custom", label: "Custom" }]}
+ />
+
+ {customEdidValue !== null && (
+ <>
+
+
setCustomEdidValue(e.target.value)}
+ />
+
+ handleEDIDChange(customEdidValue)}
+ />
+ {
+ setCustomEdidValue(null);
+ handleEDIDChange(defaultEdid);
+ }}
+ />
+
+ >
+ )}
+
+
+ {isOnDevice && (
+ <>
+
+
+
+
+
+
+
+
+
+
+ Cloud Security
+
+
+
+ • End-to-end encryption using WebRTC (DTLS and SRTP)
+ • Zero Trust security model
+ • OIDC (OpenID Connect) authentication
+ • All streams encrypted in transit
+
+
+
+
+ All cloud components are open-source and available on{" "}
+
+ GitHub
+
+ .
+
+
+
+
+
+
+
+
+
+
+
+ {!isAdopted ? (
+
+
+
+ ) : (
+
+
+
+ Your device is adopted to JetKVM Cloud
+
+
+ {
+ if (deviceId) {
+ if (
+ window.confirm(
+ "Are you sure you want to de-register this device?",
+ )
+ ) {
+ deregisterDevice();
+ }
+ } else {
+ notifications.error("No device ID available");
+ }
+ }}
+ />
+
+
+
+ )}
+
+ >
+ )}
+
+ {isOnDevice ? (
+ <>
+
+
+
+
+
+ {localDevice?.authMode === "password" ? (
+ {
+ setLocalAuthModalView("deletePassword");
+ setIsLocalAuthDialogOpen(true);
+ }}
+ />
+ ) : (
+ {
+ setLocalAuthModalView("createPassword");
+ setIsLocalAuthDialogOpen(true);
+ }}
+ />
+ )}
+
+
+ {localDevice?.authMode === "password" && (
+
+ {
+ setLocalAuthModalView("updatePassword");
+ setIsLocalAuthDialogOpen(true);
+ }}
+ />
+
+ )}
+
+
+
+ >
+ ) : null}
+
+
+
+
+
+ {
+ handleAutoUpdateChange(e.target.checked);
+ }}
+ />
+
+
+ {
+ handleDevChannelChange(e.target.checked);
+ }}
+ />
+
+
+
+
+
+
+
+ {
+ setCurrentTheme(e.target.value);
+ handleThemeChange(e.target.value);
+ }}
+ />
+
+
+
+
+
+
+
+ handleDevModeChange(e.target.checked)}
+ />
+
+
+ {settings.developerMode && (
+
+
handleSSHKeyChange(e.target.value)}
+ placeholder="Enter your SSH public key"
+ />
+
+ The default SSH user is root .
+
+
+
+
+
+ )}
+ {settings.developerMode && (
+
+
handleUsbVendorIdChange(e.target.value)}
+ placeholder="Enter USB Vendor Id"
+ />
+ handleUsbProductIdChange(e.target.value)}
+ placeholder="Enter USB Product Id"
+ />
+ handleUsbSerialChange(e.target.value)}
+ placeholder="Enter USB Serial Number"
+ />
+ handleUsbName(e.target.value)}
+ placeholder="Enter USB Name"
+ />
+ handleUsbManufacturer(e.target.value)}
+ placeholder="Enter USB Manufacturer"
+ />
+
+ {
+ if (Object.values(usbConfig).every(function(i) { return Boolean(i); })) {
+ handleUsbConfigChange(usbConfig);
+ notifications.success("Successfully updated USB Config")
+ } else {
+ notifications.error("Failed to update USB config");
+ }
+ }}
+ />
+
+
+ )}
+
+ {
+ settings.setDebugMode(e.target.checked);
+ }}
+ />
+
+
+ {settings.debugMode && (
+ <>
+
+ handleUsbEmulationToggle(!usbEmulationEnabled)}
+ />
+
+ >
+ )}
+ {settings.debugMode && (
+
+ {
+ handleResetConfig();
+ window.location.reload();
+ }}
+ />
+
+ )}
+
+
{
+ // Revalidate the current route to refresh the local device status and dependent UI components
+ revalidator.revalidate();
+ setIsLocalAuthDialogOpen(x);
+ }}
+ />
- {
- // Revalidate the current route to refresh the local device status and dependent UI components
- revalidator.revalidate();
- setIsLocalAuthDialogOpen(x);
- }}
- />
-
);
-}
+}
\ No newline at end of file
diff --git a/usb.go b/usb.go
index 075409a..18bf874 100644
--- a/usb.go
+++ b/usb.go
@@ -3,6 +3,7 @@ package kvm
import (
"errors"
"fmt"
+ gadget "github.com/openstadia/go-usb-gadget"
"log"
"os"
"os/exec"
@@ -11,8 +12,6 @@ import (
"strings"
"sync"
"time"
-
- gadget "github.com/openstadia/go-usb-gadget"
)
const configFSPath = "/sys/kernel/config"
@@ -20,19 +19,6 @@ const gadgetPath = "/sys/kernel/config/usb_gadget"
const kvmGadgetPath = "/sys/kernel/config/usb_gadget/jetkvm"
const configC1Path = "/sys/kernel/config/usb_gadget/jetkvm/configs/c.1"
-func mountConfigFS() error {
- _, err := os.Stat(gadgetPath)
- if os.IsNotExist(err) {
- err = exec.Command("mount", "-t", "configfs", "none", configFSPath).Run()
- if err != nil {
- return fmt.Errorf("failed to mount configfs: %w", err)
- }
- } else {
- return fmt.Errorf("unable to access usb gadget path: %w", err)
- }
- return nil
-}
-
func init() {
_ = os.MkdirAll(imagesFolder, 0755)
udcs := gadget.GetUdcs()
@@ -58,6 +44,60 @@ func init() {
//TODO: read hid reports(capslock, numlock, etc) from keyboardHidFile
}
+func UpdateGadgetConfig() error {
+ LoadConfig()
+ gadgetAttrs := [][]string{
+ {"idVendor", config.UsbConfig.UsbVendorId},
+ {"idProduct", config.UsbConfig.UsbProductId},
+ }
+ err := writeGadgetAttrs(kvmGadgetPath, gadgetAttrs)
+ if err != nil {
+ return err
+ }
+
+ log.Printf("Successfully updated usb gadget attributes: %v", gadgetAttrs)
+
+ strAttrs := [][]string{
+ {"serialnumber", config.UsbConfig.UsbSerialNumber},
+ {"manufacturer", config.UsbConfig.UsbManufacturer},
+ {"product", config.UsbConfig.UsbName},
+ }
+ gadgetStringsPath := filepath.Join(kvmGadgetPath, "strings", "0x409")
+ err = os.MkdirAll(gadgetStringsPath, 0755)
+ if err != nil {
+ return err
+ }
+ err = writeGadgetAttrs(gadgetStringsPath, strAttrs)
+ if err != nil {
+ return err
+ }
+
+ log.Printf("Successfully updated string attributes: %s", strAttrs)
+
+ err = rebindUsb()
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func mountConfigFS() error {
+ logger.Infof("Checking for gadgetPath: %s ...", gadgetPath)
+ _, err := os.Stat(gadgetPath)
+ if os.IsNotExist(err) {
+ logger.Infof("running mount command...")
+ err = exec.Command("mount", "-t", "configfs", "none", configFSPath).Run()
+ if err != nil {
+ return fmt.Errorf("failed to mount configfs: %w", err)
+ }
+ } else {
+ return fmt.Errorf("unable to access usb gadget path: %w", err)
+ }
+ logger.Infof("Successfully mounted usb gadget at %s", gadgetPath)
+ return nil
+}
+
func writeGadgetAttrs(basePath string, attrs [][]string) error {
for _, item := range attrs {
filePath := filepath.Join(basePath, item[0])
@@ -79,30 +119,35 @@ func writeGadgetConfig() error {
return err
}
- err = writeGadgetAttrs(kvmGadgetPath, [][]string{
- {"bcdUSB", "0x0200"}, //USB 2.0
- {"idVendor", "0x1d6b"}, //The Linux Foundation
- {"idProduct", "0104"}, //Multifunction Composite Gadget¬
+ LoadConfig()
+ gadgetAttrs := [][]string{
+ {"bcdUSB", "0x0200"}, //USB 2.0
+ {"idVendor", config.UsbConfig.UsbVendorId},
+ {"idProduct", config.UsbConfig.UsbProductId},
{"bcdDevice", "0100"},
- })
+ }
+ err = writeGadgetAttrs(kvmGadgetPath, gadgetAttrs)
if err != nil {
return err
}
+ logger.Infof("Successfully wrote gadget attributes: %s", gadgetAttrs)
gadgetStringsPath := filepath.Join(kvmGadgetPath, "strings", "0x409")
err = os.MkdirAll(gadgetStringsPath, 0755)
if err != nil {
return err
}
- err = writeGadgetAttrs(gadgetStringsPath, [][]string{
- {"serialnumber", GetDeviceID()},
- {"manufacturer", "JetKVM"},
- {"product", "JetKVM USB Emulation Device"},
- })
+ strAttrs := [][]string{
+ {"serialnumber", config.UsbConfig.UsbSerialNumber},
+ {"manufacturer", config.UsbConfig.UsbManufacturer},
+ {"product", config.UsbConfig.UsbName},
+ }
+ err = writeGadgetAttrs(gadgetStringsPath, strAttrs)
if err != nil {
return err
}
+ logger.Infof("Successfully wrote string attributes: %s", strAttrs)
configC1StringsPath := path.Join(configC1Path, "strings", "0x409")
err = os.MkdirAll(configC1StringsPath, 0755)
@@ -216,11 +261,27 @@ func writeGadgetConfig() error {
}
func rebindUsb() error {
+ unbindErr := unbindUsb()
+ if unbindErr != nil {
+ return unbindErr
+ }
+ bindErr := bindUsb()
+ if bindErr != nil {
+ return bindErr
+ }
+ return nil
+}
+
+func unbindUsb() error {
err := os.WriteFile("/sys/bus/platform/drivers/dwc3/unbind", []byte(udc), 0644)
if err != nil {
return err
}
- err = os.WriteFile("/sys/bus/platform/drivers/dwc3/bind", []byte(udc), 0644)
+ return nil
+}
+
+func bindUsb() error {
+ err := os.WriteFile("/sys/bus/platform/drivers/dwc3/bind", []byte(udc), 0644)
if err != nil {
return err
}