Skip to content

Commit e4f4c4e

Browse files
committed
chore: get device id moved to node
1 parent 8e1078b commit e4f4c4e

File tree

3 files changed

+87
-14
lines changed

3 files changed

+87
-14
lines changed

src-node/utils.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,7 @@ async function addDeviceLicense() {
316316
const dir = path.dirname(targetPath);
317317
// POSIX: mkdir + printf (use absolute paths)
318318
const safe = content.replace(/'/g, `'\\''`);
319+
// todo we need to chmod to make this world readable
319320
command = `/bin/mkdir -p "${dir}" && /bin/printf '%s' '${safe}' > "${targetPath}"`;
320321
}
321322

@@ -349,6 +350,51 @@ async function isLicensedDevice() {
349350
}
350351
}
351352

353+
async function _getLinuxDeviceID() {
354+
const data = await fsPromise.readFile("/etc/machine-id", "utf8");
355+
const id = data.trim();
356+
return id || null;
357+
// throw on error to main.
358+
// no fallback, /var/lib/dbus/machine-id may need sudo in some machines
359+
}
360+
361+
/**
362+
* Get the macOS device ID (IOPlatformUUID).
363+
* @returns {Promise<string|null>}
364+
*/
365+
function _getMacDeviceID() {
366+
return new Promise((resolve, reject) => {
367+
exec(
368+
'ioreg -rd1 -c IOPlatformExpertDevice | grep IOPlatformUUID',
369+
{ encoding: 'utf8' },
370+
(err, stdout) => {
371+
if (err) {
372+
console.error('Failed to get Mac device ID:', err.message);
373+
return reject(err);
374+
}
375+
376+
const match = stdout.match(/"IOPlatformUUID" = "([^"]+)"/);
377+
if (match && match[1]) {
378+
resolve(match[1]);
379+
} else {
380+
resolve(null);
381+
}
382+
}
383+
);
384+
});
385+
}
386+
387+
async function getDeviceID() {
388+
if (process.platform === "linux") {
389+
return _getLinuxDeviceID();
390+
} else if (process.platform === "darwin") {
391+
return _getMacDeviceID();
392+
} else if (process.platform === "win32") {
393+
return "not implemented"; //await _getWindowsDeviceID();
394+
}
395+
throw new Error(`Unsupported platform: ${process.platform}`);
396+
}
397+
352398
exports.getURLContent = getURLContent;
353399
exports.setLocaleStrings = setLocaleStrings;
354400
exports.getPhoenixBinaryVersion = getPhoenixBinaryVersion;
@@ -361,5 +407,6 @@ exports.openInDefaultApp = openInDefaultApp;
361407
exports.addDeviceLicense = addDeviceLicense;
362408
exports.removeDeviceLicense = removeDeviceLicense;
363409
exports.isLicensedDevice = isLicensedDevice;
410+
exports.getDeviceID = getDeviceID;
364411
exports._loadNodeExtensionModule = _loadNodeExtensionModule;
365412
exports._npmInstallInFolder = _npmInstallInFolder;

src/services/login-service.js

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -216,27 +216,27 @@ define(function (require, exports, module) {
216216
}
217217
}
218218

219-
async function _getLinuxDeviceID() {
220-
const LINUX_DEVICE_ID_FILE = Phoenix.VFS.getTauriVirtualPath('/etc/machine-id');
221-
const result = await Phoenix.VFS.readFileResolves(LINUX_DEVICE_ID_FILE, 'utf8');
222-
if(result.error || !result.data) {
223-
logger.reportError(result.error, `Failed to read machine-id file for licensing`);
224-
return null;
225-
}
226-
return KernalModeTrust.generateDataSignature(result.data.trim()); // \n and spaces are trimmed, just id please
227-
}
228-
229-
let deviceIDCached = null;
219+
let deviceIDCached = undefined;
230220
async function getDeviceID() {
231221
if(!Phoenix.isNativeApp) {
232222
// We only grant device licenses to desktop apps. Browsers cannot be uniquely device identified obviously.
233223
return null;
234224
}
235-
if(deviceIDCached) {
225+
if(deviceIDCached !== undefined) {
236226
return deviceIDCached;
237227
}
238-
switch (Phoenix.platform) {
239-
case 'linux': deviceIDCached = await _getLinuxDeviceID();
228+
try {
229+
const deviceID = await NodeUtils.getDeviceID();
230+
if(!deviceID) {
231+
deviceIDCached = null;
232+
Metrics.countEvent(Metrics.EVENT_TYPE.AUTH, "deviceID", "nullErr");
233+
return null;
234+
}
235+
deviceIDCached = KernalModeTrust.generateDataSignature(deviceID);
236+
} catch (e) {
237+
logger.reportError(e, "failed to sign deviceID");
238+
Metrics.countEvent(Metrics.EVENT_TYPE.AUTH, "deviceID", "SignErr");
239+
deviceIDCached = null;
240240
}
241241
return deviceIDCached;
242242
}

src/utils/NodeUtils.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,31 @@ define(function (require, exports, module) {
191191
return utilsConnector.execPeer("openInDefaultApp", window.fs.getTauriPlatformPath(fullPath));
192192
}
193193

194+
195+
let cachedDeviceID = undefined;
196+
/**
197+
* gets the os device id. this usually won't change till os reinstall.
198+
*
199+
* @returns {Promise<string|null>} - Resolves with the os identifier or null
200+
* @throws {Error} - If called from the browser
201+
*/
202+
async function getDeviceID() {
203+
if (!Phoenix.isNativeApp) {
204+
throw new Error("getDeviceID not available in browser");
205+
}
206+
if(cachedDeviceID !== undefined) {
207+
return cachedDeviceID;
208+
}
209+
try {
210+
cachedDeviceID = await utilsConnector.execPeer("getDeviceID");
211+
return cachedDeviceID;
212+
} catch (err) {
213+
cachedDeviceID = null;
214+
logger.reportError(err, "getDeviceID failed in NodeUtils");
215+
}
216+
return cachedDeviceID;
217+
}
218+
194219
/**
195220
* Enables device license by creating a system-wide license file.
196221
* On Windows, macOS, and Linux this will request elevation if needed.
@@ -291,6 +316,7 @@ define(function (require, exports, module) {
291316
exports.addDeviceLicenseSystemWide = addDeviceLicenseSystemWide;
292317
exports.removeDeviceLicenseSystemWide = removeDeviceLicenseSystemWide;
293318
exports.isLicensedDeviceSystemWide = isLicensedDeviceSystemWide;
319+
exports.getDeviceID = getDeviceID;
294320

295321
/**
296322
* checks if Node connector is ready

0 commit comments

Comments
 (0)